﻿using IDEAMS.common.control;
using IDEAMS.core;
using IDEAMS.core.deviceClient;
using IDEAMS.core.opm;
using IDEAMS.core.queue;
using IDEAMS.model;
using IDEAMS.model.alarm;
using IDEAMS.model.device;
using IDEAMS.model.spectrum;
using IDEAMS.model.waveLen;
using IDEAMS.utils;
using IDEAMS.view;
using IDEAMS.view.detection;
using IDEAMS.view.setting;
using log4net;
using Microsoft.Win32;
using RealTimeCharts.LineChart;
using RealTimeCharts.LineChart.common;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing;
using System.Linq;
using System.Media;
using System.Speech.Synthesis;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using IDEAMS.common;
using IDEAMS.view.alarm;
using System.Diagnostics;
using System.IO;
using IDEAMS.common.converter;
using System.Windows.Data;
using System.Windows.Media.Imaging;
using IDEAMS.model.setting;



namespace IDEAMS
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private ILog logger = null;

        private DevicePanel selectDevicePanel;
        private DeviceInfoViewModel selectDeviceInfo;

        public MainWindowViewModel windowViewModel;

        private readonly object gsLocker = new object(); //光谱图的locker
        private readonly object peaksLocker = new object(); //peaks 发现的locker

        /// <summary>
        /// 光谱接收线程
        /// </summary>
        OPM_MsgWorker chartRefreshMsgWorker = null; 
        /// <summary>
        /// 波长接收线程
        /// </summary>
        OPM_MsgWorker peaksRefreshMsgWorker = null;

        /// <summary>
        /// 光谱刷新线程
        /// </summary>
        private Thread timerThread = null;
        private bool timerThreadStopFlag = false;

        /// <summary>
        /// 报警列表
        /// </summary>
        HashSet<string> alarmDevices = new HashSet<string>();

        /// <summary>
        /// 检验按钮
        /// </summary>
        Button toolPreDataAcquisition;
        Button toolPreEtalonText;
        Button toolPreSpectrumGrating;
        Button toolPreSpectrumNoGrating;
        Button toolContinuousDetection;
        Button toolPostSpectrumNoGrating;
        Button toolPostSpectrumGrating;
        Button toolPostEtalonText;
        Button toolPostDataAcquisition;
        private Dictionary<ProcessStep, Button> toolButtonDic;


        public MainWindow()
        {
            InitializeComponent();

            logger = LogManager.GetLogger(typeof(MainWindow));

            this.Loaded += MainWindow_Loaded;
            this.Closing += new System.ComponentModel.CancelEventHandler(Window_Closing);

            this.spectrumCanvas.SizeChanged += new SizeChangedEventHandler(SpectrumCanvas_SizeChanged);
            this.waveLenCanvas.SizeChanged += new SizeChangedEventHandler(WaveLenCanvas_SizeChanged);

            this.menuGlobalSetting.Click += new RoutedEventHandler(GlobalSetting_Click);
            this.menuEtalonSetting.Click += new RoutedEventHandler(EtalonSetting_Click);
            this.menuAddDevice.Click += new RoutedEventHandler(AddDevice_Click);

            this.menuInspectionSequence.Click += new RoutedEventHandler(InspectionSequence_Click);

            this.menuRoasterRecord.Click += new RoutedEventHandler(RoasterRecord_Click);
            //this.menuAlarmRecord.Click += new RoutedEventHandler(AlarmRecord_Click);

            this.menuClose.Click += new RoutedEventHandler(Close_Click);

            this.menuHelp.Click += new RoutedEventHandler(HelpFile_Click);
            this.menuAbout.Click += new RoutedEventHandler(About_Click);

            this.toolAddDevice.Click += new RoutedEventHandler(AddDevice_Click);
            this.toolDeleteDevice.Click += new RoutedEventHandler(DeleteDevice_Click);
            this.toolEditDeviceIp.Click += new RoutedEventHandler(EditDeviceIp_Click);

            this.btnChannelConfSetting.Click += new RoutedEventHandler(ChannelConfSetting_Click);
            this.btnRefreshSpectum.Click += new RoutedEventHandler(RefreshSpectrum_Click);

            this.cbChannel.SelectionChanged += new SelectionChangedEventHandler(Channel_SelectionChanged);

            this.cbGratting.SelectionChanged += new SelectionChangedEventHandler(Grating_SelectionChanged);

            #region  检验

            this.toolAntiAlarm.Click += new RoutedEventHandler(AntiAlarm_Click);
            this.toolAlarmRecord.Click += new RoutedEventHandler(AlarmRecord_Click);
            this.toolRollback.Click += new RoutedEventHandler(Rollback_Click);
            this.toolReText.Click += new RoutedEventHandler(ReText_Click);
            this.toolFinished.Click += new RoutedEventHandler(Finished_Click);
            this.toolCreateReport.Click += new RoutedEventHandler(CreateReport_Click);
            this.toolRoasterRecord.Click += new RoutedEventHandler(RoasterRecord_Click);
            #endregion

            int rn = TW_App.Init();
            if (rn != 0)
            {
                string errMsg = "程序初始化失败";
                logger.ErrorFormat(errMsg);
                MessageBox.Show(errMsg, "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }

            windowViewModel = new MainWindowViewModel();
            this.DataContext = windowViewModel;

            this.wpDevicePanel.Children.Clear();
            for (int i = 0; i < windowViewModel.deviceInfos.Count; i++)
            {
                DevicePanel panel = new DevicePanel();
                panel.Width = 180;
                panel.Height = 180;
                panel.DeviceInfo = windowViewModel.deviceInfos[i];
                panel.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(DevicePanel_MouseLeftButtonDown);
                wpDevicePanel.Children.Add(panel);
            }

            chSeriesColor = MakeLegendColorTable();

            InitChart();

            Log.SetTextControl(alarmLogger);
            this.alarmLogger.Height = 0;

            CreateToolBarButton();


            //this.checkToolBar.Items.Add(this.toolPreEtalonText);
            //this.checkToolBar.Items.Add(this.toolPreSpectrumGrating);
            //this.checkToolBar.Items.Add(this.toolPreSpectrumNoGrating);
            //this.checkToolBar.Items.Add(this.toolContinuousDetection);
            //this.checkToolBar.Items.Add(this.toolPostSpectrumNoGrating);
            //this.checkToolBar.Items.Add(this.toolPostSpectrumGrating);
            //this.checkToolBar.Items.Add(this.toolPostEtalonText);

            btnEnableSetting(ProcessStep.NOT_STARTED);

            AddToolButton();

        }

        private void AddToolButton()
        {
            this.checkToolBar.Items.Clear();

            for(int i = 0;i< TW_App.globalSetting.inspectionSequences.Count;i++) 
            {
                if (toolButtonDic.ContainsKey((ProcessStep)TW_App.globalSetting.inspectionSequences[i]))
                {
                    this.checkToolBar.Items.Remove(toolButtonDic[(ProcessStep)TW_App.globalSetting.inspectionSequences[i]]);
                    this.checkToolBar.Items.Add(toolButtonDic[(ProcessStep)TW_App.globalSetting.inspectionSequences[i]]);
                }
            }
        } 

        private void CreateToolBarButton()
        {
            // 添加按钮
            this.toolPreDataAcquisition = CreateButton(this.checkToolBar, "采集(前)", "/resources/images/dataAcquisition32.png", "/resources/images/dataAcquisition32_2.png", "toolPreDataAcquisition");
            this.toolPreEtalonText = CreateButton(this.checkToolBar, "标准具(前)", "/resources/images/etalon32.png", "/resources/images/etalon32_2.png", "toolPreEtalonText");
            this.toolPreSpectrumGrating = CreateButton(this.checkToolBar, "有栅谱(前)", "/resources/images/spectrum32.png", "/resources/images/spectrum32_2.png", "toolPreSpectrumGrating");
            this.toolPreSpectrumNoGrating = CreateButton(this.checkToolBar, "无栅谱(前)", "/resources/images/noSpectrum32.png", "/resources/images/noSpectrum32_2.png", "toolPreSpectrumNoGrating");
            this.toolContinuousDetection = CreateButton(this.checkToolBar, "烤机检测", "/resources/images/continuous32.png", "/resources/images/continuous32_2.png", "toolContinuousDetection");
            this.toolPostSpectrumNoGrating = CreateButton(this.checkToolBar, "无栅谱(后)", "/resources/images/noSpectrum32.png", "/resources/images/noSpectrum32_2.png", "toolPostSpectrumNoGrating");
            this.toolPostSpectrumGrating = CreateButton(this.checkToolBar, "有栅谱(后)", "/resources/images/spectrum32.png", "/resources/images/spectrum32_2.png", "toolPostSpectrumGrating");
            this.toolPostEtalonText = CreateButton(this.checkToolBar, "标准具(后)", "/resources/images/etalon32.png", "/resources/images/etalon32_2.png", "toolPostEtalonText");
            this.toolPostDataAcquisition = CreateButton(this.checkToolBar, "采集(后)", "/resources/images/dataAcquisition32.png", "/resources/images/dataAcquisition32_2.png", "toolPostDataAcquisition");

            this.toolPreDataAcquisition.Click += new RoutedEventHandler(PreDataAcquisition_Click);
            this.toolPreEtalonText.Click += new RoutedEventHandler(PreEtalonText_Click);
            this.toolPreSpectrumGrating.Click += new RoutedEventHandler(PreSpectrumGrating_Click);
            this.toolPreSpectrumNoGrating.Click += new RoutedEventHandler(PreSpectrumNoGrating_Click);
            this.toolContinuousDetection.Click += new RoutedEventHandler(ContinuousDetection_Click);
            this.toolPostSpectrumNoGrating.Click += new RoutedEventHandler(PostSpectrumNoGrating_Click);
            this.toolPostSpectrumGrating.Click += new RoutedEventHandler(PostSpectrumGrating_Cilck);
            this.toolPostEtalonText.Click += new RoutedEventHandler(PostEtalonText_Click);
            this.toolPostDataAcquisition.Click += new RoutedEventHandler(PostDataAcquisition_Click);

            toolButtonDic = new Dictionary<ProcessStep, Button>();
            toolButtonDic.Add(ProcessStep.PRE_DATA_ACQUISITION,this.toolPreDataAcquisition);
            toolButtonDic.Add(ProcessStep.PRE_ETALON, this.toolPreEtalonText);
            toolButtonDic.Add(ProcessStep.PRE_SPECTRUM_GRATING, this.toolPreSpectrumGrating);
            toolButtonDic.Add(ProcessStep.PRE_SPECTRUM_NO_GRATING, this.toolPreSpectrumNoGrating);
            toolButtonDic.Add(ProcessStep.CONTINUOUS_DETECTION, this.toolContinuousDetection);
            toolButtonDic.Add(ProcessStep.POST_SPECTRUM_NO_GRATING, this.toolPostSpectrumNoGrating);
            toolButtonDic.Add(ProcessStep.POST_SPECTRUM_GRATING, this.toolPostSpectrumGrating);
            toolButtonDic.Add(ProcessStep.POST_ETALON, this.toolPostEtalonText);
            toolButtonDic.Add(ProcessStep.POST_DATA_ACQUISITION, this.toolPostDataAcquisition);
        }

        private void EditDeviceIp_Click(object sender, RoutedEventArgs e)
        {
            if (selectDeviceInfo == null)
                return;
            EditDeviceIpDlg dlg = new EditDeviceIpDlg(selectDeviceInfo);
            dlg.Owner = this;
            dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            bool? result = dlg.ShowDialog();
            if(result == true)
            {
                selectDeviceInfo.deviceParam.destIP = dlg.windowViewModel.deviceIp;
                selectDeviceInfo.ip = dlg.windowViewModel.deviceIp;
                DeviceClient client = TW_App.deviceClientManager.Find(selectDeviceInfo.serialNo);
                //client.Stop();
                client.ip = dlg.windowViewModel.deviceIp;
                client.dataWorker.ip = dlg.windowViewModel.deviceIp;
                TW_App.deviceInfoCollection.Update(selectDeviceInfo.serialNo, new DeviceInfo(selectDeviceInfo));
                TW_App.deviceInfoCollection.Save();
            }
        }

        private Button CreateButton(ToolBar toolBar, string text, string imagePathEnabled, string imagePathDisabled, string buttonName)
        {
            // 创建 Button
            Button button = new Button
            {
                Width = 64,
                Height = 64,
                Margin = new Thickness(2),
                Name = buttonName
            };

            // 创建 DockPanel
            DockPanel dockPanel = new DockPanel
            {
                LastChildFill = false
            };

            // 创建 Image
            System.Windows.Controls.Image image = new System.Windows.Controls.Image
            {
                Width = 32,
                Height = 32,
                Source = new BitmapImage(new Uri(imagePathEnabled, UriKind.Relative))
            };

            // 绑定 Image 的 Source
            Binding binding = new Binding("IsEnabled")
            {
                RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(Button), 1),
                Converter = new BoolToImageSourceConverter(),
                ConverterParameter = $"{imagePathEnabled}:{imagePathDisabled}"
            };
            image.SetBinding(System.Windows.Controls.Image.SourceProperty, binding);

            // 创建 TextBlock
            TextBlock textBlock = new TextBlock
            {
                Text = text,
                HorizontalAlignment = HorizontalAlignment.Center
            };

            // 将 Image 和 TextBlock 添加到 DockPanel
            DockPanel.SetDock(image, Dock.Top);
            DockPanel.SetDock(textBlock, Dock.Top);
            dockPanel.Children.Add(image);
            dockPanel.Children.Add(textBlock);

            // 将 DockPanel 设置为 Button 的内容
            button.Content = dockPanel;

            return button;
            //// 将 Button 添加到 ToolBar
            //toolBar.Items.Add(button);
        }

        #region 用户交换

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            CreateChartSpectrum(false);
            CreateChartWaveLen(false);

            StartChartRefreshWorker();
            StartPeaksRefreshWorker();

            timerThread = new Thread(new ThreadStart(() => TimerThreadProc()));
            if (timerThread != null)
            {
                timerThread.Start();
                timerThreadStopFlag = false;
            }

            TW_App.delegateCollection.readChParameterEvent += ReadChRarameterEvent;
            TW_App.delegateCollection.settingChParameterEvent += SettingChParameterEvent;
            TW_App.delegateCollection.connectionStatusChangeEvent += ConnectionStatusChangeEvent;
            TW_App.delegateCollection.alarmEvent += WaveLenAlarmEvent;
            TW_App.delegateCollection.continuousTimeEvent += ContinuousTimeEvent;
            TW_App.delegateCollection.sendDeviceParamEvent += SaveDeviceParamEvent;
            TW_App.delegateCollection.sendDeviceFrequencyEvent += SaveDeviceFrequencyEvent;

            TW_App.StartAllDeviceClients(TW_App.deviceInfoCollection);

        }

        private void SaveDeviceParamEvent(DeviceParam deviceParam)
        {
            DeviceInfo info = TW_App.deviceInfoCollection.Find(deviceParam.serialNo);
            if (info != null)
            {
                info.deviceParam.Copy(deviceParam);
                TW_App.deviceInfoCollection.Save();
            }
            foreach (var item in windowViewModel.deviceInfos)
            {
                if (item.serialNo.Equals(deviceParam.serialNo))
                {
                    item.deviceParam.Copy(deviceParam);
                    break;
                }
            }
        }

        private void SaveDeviceFrequencyEvent(string serialNo, int frequency)
        {
            DeviceInfo info = TW_App.deviceInfoCollection.Find(serialNo);
            if (info != null)
            {
                info.frequency = frequency;
                TW_App.deviceInfoCollection.Save();
            }
            foreach (var item in windowViewModel.deviceInfos)
            {
                if (item.serialNo.Equals(serialNo))
                {
                    item.frequency = frequency;
                    break;
                }
            }
        }

        private void ContinuousTimeEvent(string serialNo, double time)
        {
            Console.WriteLine("接收时间：" + DateTime.Now.ToString("HH:mm:ss.fff"));
            foreach (DeviceInfoViewModel item in windowViewModel.deviceInfos)
            {
                if (item.serialNo.Equals(serialNo))
                {
                    if(item.isBreak == true && time - item.continuousRunTime > 2 / 60)
                    {
                        AlarmInfo alarmInfo = new AlarmInfo();
                        alarmInfo.serialNo = serialNo;
                        alarmInfo.type = AlarmType.CONNECTED_ERROR;
                        alarmInfo.key = ProcessStep.CONTINUOUS_DETECTION + "_" + AlarmType.CONNECTED_ERROR;
                        alarmInfo.channelNo = 0;
                        alarmInfo.gratingNo = 0;
                        alarmInfo.step = ProcessStep.CONTINUOUS_DETECTION;
                        alarmInfo.maxDiff = time - item.continuousRunTime;
                        alarmInfo.startTime = DateTime.Now;
                        alarmInfo.endTime = DateTime.Now;
                        alarmInfo.description = string.Format("网络连接中断了{0}小时。", time-item.continuousRunTime);
                        WaveLenAlarmEvent(alarmInfo);
                    }
                    item.isBreak = false;

                    item.continuousRunTime = time;
                    if(time > item.maxContinuousRunTime)
                    {
                        item.maxContinuousRunTime = time;
                    }
                    if(time > TW_App.globalSetting.continuousRunTime)
                    {
                        if (item.status != model.DeviceStatus.ALARM)
                        {
                            item.status = model.DeviceStatus.KJ_FINISH;
                        }
                        Thread thread = new Thread(new ThreadStart(() =>
                        {
                            PlayFinishSound(serialNo, TW_App.globalSetting.continuousRunTime);
                        }));
                        thread.Start();

                    }
                    TW_App.deviceInfoCollection.Update(serialNo, new DeviceInfo(item));
                    TW_App.deviceInfoCollection.Save();
                    break;
                }
            }

            TW_App.deviceInfoCollection.Save();
        }

        /// <summary>
        /// 播放烤机完成声音
        /// </summary>
        /// <param name="serialNo"></param>
        /// <param name="time"></param>
        private void PlayFinishSound(string serialNo,double time)
        {
            lock(soundLocker)
            {
                string soundPath = TW_App.fileManager.soundPath + "\\y2181.wav";
                SoundPlayer player = new SoundPlayer(soundPath);
                // 创建一个 SpeechSynthesizer 对象
                using (SpeechSynthesizer synth = new SpeechSynthesizer())
                {
                    // 设置语音合成器的属性
                    synth.SetOutputToDefaultAudioDevice(); // 设置输出到默认音频设备

                    // 播放提示音
                    player.Play();

                    // 等待提示音播放完毕
                    player.PlaySync();

                    // 要合成的文本
                    string text = "序列号为" + serialNo + "的设备烤机时间已到达" + time.ToString("F2") + "小时。";

                    // 合成并播放文本
                    synth.Speak(text);
                }
            }
        }

        private object soundLocker = new object();
        private bool isSound = false;
        /// <summary>
        /// 播放报警声音
        /// </summary>
        /// <param name="serialNo"></param>
        /// <param name="time"></param>
        private void PlayAlarmSound(AlarmInfo info)
        {
            if (isSound) return;
            isSound = true;
            lock (soundLocker)
            {
                if (TW_App.globalSetting.alarmSoundOn)
                {
                    string soundPath = TW_App.fileManager.soundPath + "\\xm2779.wav";
                    SoundPlayer player = new SoundPlayer(soundPath);
                    // 创建一个 SpeechSynthesizer 对象
                    using (SpeechSynthesizer synth = new SpeechSynthesizer())
                    {
                        // 设置语音合成器的属性
                        synth.SetOutputToDefaultAudioDevice(); // 设置输出到默认音频设备

                        // 播放提示音
                        player.Play();

                        // 等待提示音播放完毕
                        player.PlaySync();

                        // 要合成的文本
                        string text = "序列号为" + info.serialNo + "的设备发现异常，详情请查看报警记录。";

                        // 合成并播放文本
                        synth.Speak(text);

                    }
                }
            }
            isSound = false;
        }

        
        private void WaveLenAlarmEvent(AlarmInfo info)
        {
                string serialNo = info.serialNo;

                foreach (DeviceInfoViewModel item in windowViewModel.deviceInfos)
                {
                    if (item.serialNo.Equals(serialNo))
                    {
                        AlarmInfo alarmInfo = item.alarmInfoCollection.Find(info.key);
                        item.status = model.DeviceStatus.ALARM;
                        DeviceInfo tInfo = TW_App.deviceInfoCollection.Find(serialNo);
                        if (tInfo != null)
                            alarmDevices.Add(serialNo);

                        if (alarmInfo != null)
                        {
                            alarmInfo.endTime = info.endTime;

                            if (Math.Abs(alarmInfo.maxDiff) < Math.Abs(info.maxDiff))
                            {
                                alarmInfo.maxDiff = info.maxDiff;
                            }

                            item.alarmInfoCollection.Save(serialNo);
                            DeviceInfo deviceInfo = TW_App.deviceInfoCollection.Find(serialNo);
                            deviceInfo.alarmInfoCollection.Update(alarmInfo.key, alarmInfo);
                        }
                        else
                        {
                            item.alarmInfoCollection.Add(info);
                            item.alarmInfoCollection.Save(serialNo);
                            DeviceInfo deviceInfo = TW_App.deviceInfoCollection.Find(serialNo);
                            deviceInfo.alarmInfoCollection.Add(info);
                        }
                        break;
                    }
                }

            if (isSound) return;
            Thread thread = new Thread(new ThreadStart(() =>
            {
                PlayAlarmSound(info);
            }));
            thread.Start();
        }

        private void Window_Closing(object sender, CancelEventArgs e)
        {
            MessageBoxResult result = MessageBox.Show("关闭软件将会停止所有任务，确定继续吗？", "关闭软件", MessageBoxButton.YesNo);
            if(result == MessageBoxResult.No)
            {
                e.Cancel = true;
                return;
            }

            ProgressingDlg progressingDlg = new ProgressingDlg("程序", "正在结束...", new DoWorkEventHandler((object s, DoWorkEventArgs args) =>
            {
                timerThreadStopFlag = true;

                StopChartRefreshWorker();
                StopPeaksRefreshWorker();

                TW_App.delegateCollection.SyncAppClosed();
                TW_App.ProgramQuit();
                TW_App.appStatus = AppStatus.QUIT;
                TW_App.Wait(3000);
                logger.InfoFormat("主程序退出");
            }));

            progressingDlg.Owner = this;
            progressingDlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            progressingDlg.ShowDialog();
        }

        private void SpectrumCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            CreateChartSpectrum(false);
        }

        private void WaveLenCanvas_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            CreateChartWaveLen(false);
        }

        private void GlobalSetting_Click(object sender, RoutedEventArgs e)
        {
            GlobalSettingDlg dlg = new GlobalSettingDlg();
            dlg.Owner = this;
            dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            dlg.ShowDialog();
        }

        private void EtalonSetting_Click(object sender, RoutedEventArgs e)
        {
            EtalonSettingDlg dlg = new EtalonSettingDlg();
            dlg.Owner = this;
            dlg.WindowStartupLocation= WindowStartupLocation.CenterOwner;
            dlg.ShowDialog();

        }

        private void AddDevice_Click(object sender, RoutedEventArgs e)
        {
            AddDeviceDlg dlg = new AddDeviceDlg();
            dlg.Owner = this;
            dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            bool? result = dlg.ShowDialog();
            if (result == true)
            {
                //windowViewModel.Reload();
                //selectDeviceInfo = null;
                //selectDevicePanel = null;
                //this.wpDevicePanel.Children.Clear();
                //for (int i = 0; i < windowViewModel.deviceInfos.Count; i++)
                //{
                //    DevicePanel panel = new DevicePanel();
                //    panel.Width = 180;
                //    panel.Height = 180;
                //    panel.DeviceInfo = windowViewModel.deviceInfos[i];
                //    panel.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(DevicePanel_MouseLeftButtonDown);
                //    panel.IsSelected = false;
                //    wpDevicePanel.Children.Add(panel);
                //}
                DeviceInfoViewModel dvInfo = dlg.windowViewModel.deviceInfo.Clone();

                windowViewModel.deviceInfos.Add(dvInfo);
                DevicePanel panel = new DevicePanel();
                panel.Width = 180;
                panel.Height = 180;
                panel.DeviceInfo = dvInfo;
                panel.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(DevicePanel_MouseLeftButtonDown);
                panel.IsSelected = false;
                panel.DeviceInfo.connectionStatus = ConnectionStatus.CONNECTED;
                wpDevicePanel.Children.Add(panel);
                if (dvInfo.serialNo.Equals(selectDeviceInfo?.serialNo))
                {
                    selectDeviceInfo = null;
                    selectDevicePanel = null;
                }
            }
        }

        private void InspectionSequence_Click(object sender, RoutedEventArgs e)
        {
            InspectionSequenceDlg dlg = new InspectionSequenceDlg();
            dlg.Owner = this;
            dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            bool? result = dlg.ShowDialog();
            if(result == true)
            {
                AddToolButton();
            }
        }

        private void Close_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }


        private void HelpFile_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                Process helpProcess = new Process();
                helpProcess.StartInfo.FileName = Directory.GetCurrentDirectory() + "\\help\\智能设备老化监测系统使用手册.pdf";
                helpProcess.StartInfo.Verb = "Open";
                helpProcess.StartInfo.CreateNoWindow = true;
                helpProcess.Start();
            }
            catch (Exception)
            {

            }
        }

        private void About_Click(object sender, RoutedEventArgs e)
        {
            About about = new About();
            about.Owner = this;
            about.WindowStartupLocation= WindowStartupLocation.CenterOwner;
            about.ShowDialog();
        }

        private void DeleteDevice_Click(object sender, RoutedEventArgs e)
        {
            if (selectDevicePanel == null)
            {
                return;
            }
            string msg = string.Format("即将删除序列号为[{0}]的设备，是否确认删除？", selectDevicePanel.DeviceInfo.serialNo);
            MessageBoxResult result = MessageBox.Show(msg, "删除确认", MessageBoxButton.YesNo,MessageBoxImage.Question);
            if (result == MessageBoxResult.No)
            {
                return;
            }

            DeviceClient client = TW_App.deviceClientManager.Find(selectDevicePanel?.DeviceInfo.serialNo);
            if(client != null)
            {
                client.Stop();
                client.Join();
            }
            TW_App.deviceClientManager.Delete(selectDevicePanel?.DeviceInfo.serialNo);

            selectDevicePanel.MouseLeftButtonDown -= DevicePanel_MouseLeftButtonDown;
            wpDevicePanel.Children.Remove(selectDevicePanel);

            TW_App.deviceInfoCollection.Delete(selectDevicePanel.DeviceInfo.serialNo);
            TW_App.deviceInfoCollection.Save();
            windowViewModel.deviceInfos.Remove(selectDeviceInfo);

            selectDevicePanel = null;
            selectDeviceInfo = null;
        }


        private void DevicePanel_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            DevicePanel devicePanel = sender as DevicePanel;
            if (devicePanel == null) return;
            if (devicePanel.DeviceInfo.serialNo.Equals(selectDeviceInfo?.serialNo))
            {
                return;
            }
            // 取消光谱和波长的注册
            UnRegisterChartRefreshWorker();
            UnRegisterPeaksRefreshWorker();

            // 操作panel
            foreach (DevicePanel item in wpDevicePanel.Children)
            {
                item.IsSelected = false;
            }
            devicePanel.IsSelected = true;
            selectDevicePanel = devicePanel;
            selectDeviceInfo = devicePanel.DeviceInfo;

            // 注册光谱和波长
            RegisterChartRefreshWorker();
            RegisterPeaksRefreshWorker();

            windowViewModel.chParamViewModel = null;
            ReadChannelSetting();

            selectedSpectrumDic.Clear();
            SpectrumPkgBuffer pkgBuffer = new SpectrumPkgBuffer();
            int channelNo = windowViewModel.spectrumDisplayViewModel.selectedChannelItem.no;
            pkgBuffer.channelNo = channelNo;
            selectedSpectrumDic.Add(channelNo, pkgBuffer);

            ReadSpectrum();

            btnEnableSetting(selectDeviceInfo.step);

            // 清空波长图数据
            nextSeq = 0;
            waveLenLine.Clear();
        }

        private void RefreshSpectrum_Click(object sender, RoutedEventArgs e)
        {
            windowViewModel.chParamViewModel = null;
            ReadChannelSetting();

            selectedSpectrumDic.Clear();
            SpectrumPkgBuffer pkgBuffer = new SpectrumPkgBuffer();
            int channelNo = windowViewModel.spectrumDisplayViewModel.selectedChannelItem.no;
            pkgBuffer.channelNo = channelNo;
            selectedSpectrumDic.Add(channelNo, pkgBuffer);

            ReadSpectrum();
        }

        private void ChannelConfSetting_Click(object sender, RoutedEventArgs e)
        {
            if (selectDeviceInfo == null)
            {
                MessageBox.Show("未选择设备，请先选择设备","提示", MessageBoxButton.OK, MessageBoxImage.Exclamation);
                return;
            }
            DeviceClient client = TW_App.deviceClientManager.Find(selectDeviceInfo?.serialNo);
            if(client == null)
            {
                MessageBox.Show("设备连接不存在", "提示", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            if(client.dataWorker.GetStatus() == ConnectionStatus.OFFLINE)
            {
                MessageBox.Show("设备连接已断开，请检查设备连接", "提示", MessageBoxButton.OK, MessageBoxImage.Error);
                return;
            }
            ChannelParameter item = CreateChannelSettingItem();
            client.dataWorker.SetChannelParameter(item);
        }

        private void Channel_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            windowViewModel.chParamViewModel = null;
            ReadChannelSetting();

            selectedSpectrumDic.Clear();
            SpectrumPkgBuffer pkgBuffer = new SpectrumPkgBuffer();
            int channelNo = windowViewModel.spectrumDisplayViewModel.selectedChannelItem.no;
            pkgBuffer.channelNo = channelNo;
            selectedSpectrumDic.Add(channelNo, pkgBuffer);

            ReadSpectrum();         
        }

        private void Grating_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            nextSeq = 0;
            waveLenLine.Clear();
        }

        private void ReadChRarameterEvent(ReadChannelParameterResp resp)
        {
            if(selectDeviceInfo == null)
            {
                return;
            }

            if (!resp.serialNo.Equals(selectDeviceInfo?.serialNo))
            {
                return;
            }

            ChannelItemViewModel selectedChannel = windowViewModel.spectrumDisplayViewModel.selectedChannelItem;
            if (selectedChannel == null) return;

            int index = selectedChannel.no-1;
            if(index < resp.param.Length)
            { 
                ChParamViewModel chParamViewModel = new ChParamViewModel();
                chParamViewModel.threshold = resp.param[index].threshold / 100.0;
                chParamViewModel.refThreshold = resp.param[index].refThreshold / 100.0;
                chParamViewModel.width = resp.param[index].width / 100.0;
                chParamViewModel.widthLevel = resp.param[index].widthLevel / 100.0;
                windowViewModel.chParamViewModel = chParamViewModel;
            }

            // 清空波长图数据
            nextSeq = 0;
            waveLenLine.Clear();
        }

        private void SettingChParameterEvent()
        {
            MessageBox.Show("通道参数设置成功", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        private void ConnectionStatusChangeEvent(string serialNo, ConnectionStatus status)
        {
            if (serialNo == null) return;
            for (int i = 0; i < windowViewModel.deviceInfos.Count; i++)
            {
                if (serialNo.Equals(windowViewModel.deviceInfos[i].serialNo))
                {
                    windowViewModel.deviceInfos[i].connectionStatus = status;
                    if(status == ConnectionStatus.OFFLINE)
                    {
                        DeviceClient client = TW_App.deviceClientManager.Find(serialNo);
                        if (client != null)
                        {
                            if (client.dataWorker.isWaveStart)
                            {
                                windowViewModel.deviceInfos[i].isBreak = true;
                            }
                        }
                    }

                    break;
                }
            }
        }

        private void PreDataAcquisition_Click(object sender, RoutedEventArgs e)
        {
            DataAcquisitionDlg dlg = new DataAcquisitionDlg(selectDeviceInfo);
            dlg.Owner = this;
            dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            bool? result = dlg.ShowDialog();
            if (result == true)
            {
                DeviceInfoViewModel info = dlg.windowViewModel.deviceInfo;
                selectDeviceInfo.step = info.step;
                selectDeviceInfo.processResult.preDataAcquisition = info.processResult.preDataAcquisition;

                DeviceInfo newDevicInfo = new DeviceInfo(selectDeviceInfo);
                TW_App.deviceInfoCollection.Update(selectDeviceInfo.serialNo, newDevicInfo);
                TW_App.deviceInfoCollection.Save();

                btnEnableSetting(selectDeviceInfo.step);

                if (info.step == ProcessStep.FINISHED)
                {

                    selectDeviceInfo.status = model.DeviceStatus.FINISH;


                    selectDeviceInfo.testDate = DateTime.Now;
                    RoasterRecord roasterRecord = TW_App.roasterRecordCollection.Find(selectDeviceInfo.serialNo);
                    if (roasterRecord == null)
                    {
                        roasterRecord = new RoasterRecord();
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Add(roasterRecord);
                    }
                    else
                    {
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Update(selectDeviceInfo.serialNo, new RoasterRecord(roasterRecord));
                    }
                    TW_App.roasterRecordCollection.Save();
                    DeviceInfo deviceInfo = new DeviceInfo(selectDeviceInfo);
                    deviceInfo.Save(deviceInfo.serialNo);
                    TW_App.globalSetting.Save(deviceInfo.serialNo);
                }
            }
        }


        private void PreEtalonText_Click(object sender, RoutedEventArgs e)
        {
            EtalonTextDlg dlg = new EtalonTextDlg(selectDeviceInfo);
            dlg.Owner = this;
            dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            bool? result = dlg.ShowDialog();
            if (result == true)
            {
                DeviceInfoViewModel info = dlg.windowViewModel.deviceInfo;
                selectDeviceInfo.step = info.step;
                selectDeviceInfo.processResult.preEtalon = info.processResult.preEtalon;

                DeviceInfo newDevicInfo = new DeviceInfo(selectDeviceInfo);
                TW_App.deviceInfoCollection.Update(selectDeviceInfo.serialNo,newDevicInfo);
                TW_App.deviceInfoCollection.Save();

                btnEnableSetting(selectDeviceInfo.step);

                if (info.step == ProcessStep.FINISHED)
                {

                    selectDeviceInfo.status = model.DeviceStatus.FINISH;


                    selectDeviceInfo.testDate = DateTime.Now;
                    RoasterRecord roasterRecord = TW_App.roasterRecordCollection.Find(selectDeviceInfo.serialNo);
                    if (roasterRecord == null)
                    {
                        roasterRecord = new RoasterRecord();
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Add(roasterRecord);
                    }
                    else
                    {
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Update(selectDeviceInfo.serialNo, new RoasterRecord(roasterRecord));
                    }
                    TW_App.roasterRecordCollection.Save();
                    DeviceInfo deviceInfo = new DeviceInfo(selectDeviceInfo);
                    deviceInfo.Save(deviceInfo.serialNo);
                    TW_App.globalSetting.Save(deviceInfo.serialNo);
                }
            }
        }

        private void PreSpectrumGrating_Click(object sender, RoutedEventArgs e)
        {
            SpectrumTextDlg dlg = new SpectrumTextDlg(selectDeviceInfo);
            dlg.Owner = this;
            dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            bool? result = dlg.ShowDialog();
            if(result == true)
            {
                DeviceInfoViewModel info = dlg.windowViewModel.deviceInfo;
                selectDeviceInfo.step = info.step;
                selectDeviceInfo.processResult.preSpectrumGrating = info.processResult.preSpectrumGrating;

                DeviceInfo newDevicInfo = new DeviceInfo(selectDeviceInfo);
                TW_App.deviceInfoCollection.Update(selectDeviceInfo.serialNo, newDevicInfo);
                TW_App.deviceInfoCollection.Save();

                btnEnableSetting(selectDeviceInfo.step);
                if (info.step == ProcessStep.FINISHED)
                {

                    selectDeviceInfo.status = model.DeviceStatus.FINISH;


                    selectDeviceInfo.testDate = DateTime.Now;
                    RoasterRecord roasterRecord = TW_App.roasterRecordCollection.Find(selectDeviceInfo.serialNo);
                    if (roasterRecord == null)
                    {
                        roasterRecord = new RoasterRecord();
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Add(roasterRecord);
                    }
                    else
                    {
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Update(selectDeviceInfo.serialNo, new RoasterRecord(roasterRecord));
                    }
                    TW_App.roasterRecordCollection.Save();
                    DeviceInfo deviceInfo = new DeviceInfo(selectDeviceInfo);
                    deviceInfo.Save(deviceInfo.serialNo);
                    TW_App.globalSetting.Save(deviceInfo.serialNo);
                }

            }
        }

        private void PreSpectrumNoGrating_Click(object sender, RoutedEventArgs e)
        {
            SpectrumTextDlg dlg = new SpectrumTextDlg(selectDeviceInfo);
            dlg.Owner = this;
            dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            bool? result = dlg.ShowDialog();
            if (result == true)
            {
                DeviceInfoViewModel info = dlg.windowViewModel.deviceInfo;
                selectDeviceInfo.step = info.step;
                selectDeviceInfo.processResult.preSpectrumNoGrating = info.processResult.preSpectrumNoGrating;

                DeviceInfo newDevicInfo = new DeviceInfo(selectDeviceInfo);
                TW_App.deviceInfoCollection.Update(selectDeviceInfo.serialNo, newDevicInfo);
                TW_App.deviceInfoCollection.Save();

                btnEnableSetting(selectDeviceInfo.step);

                if (info.step == ProcessStep.FINISHED)
                {

                    selectDeviceInfo.status = model.DeviceStatus.FINISH;


                    selectDeviceInfo.testDate = DateTime.Now;
                    RoasterRecord roasterRecord = TW_App.roasterRecordCollection.Find(selectDeviceInfo.serialNo);
                    if (roasterRecord == null)
                    {
                        roasterRecord = new RoasterRecord();
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Add(roasterRecord);
                    }
                    else
                    {
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Update(selectDeviceInfo.serialNo, new RoasterRecord(roasterRecord));
                    }
                    TW_App.roasterRecordCollection.Save();
                    DeviceInfo deviceInfo = new DeviceInfo(selectDeviceInfo);
                    deviceInfo.Save(deviceInfo.serialNo);
                    TW_App.globalSetting.Save(deviceInfo.serialNo);
                }
            }
        }

        private void ContinuousDetection_Click(object sender, RoutedEventArgs e)
        {
            if(selectDeviceInfo == null)
            {
                return;
            }
            DeviceClient client = TW_App.deviceClientManager.Find(selectDeviceInfo.serialNo);
            if(client == null)
            {
                return;
            }
            if(selectDeviceInfo.connectionStatus == ConnectionStatus.OFFLINE)
            {
                MessageBox.Show("设备未连接，请先连上设备", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }
            if (client.dataWorker.isWaveStart)
            {
                ContiunousTextDlg dlg = new ContiunousTextDlg(selectDeviceInfo);
                dlg.Owner = this;
                dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
                bool? result = dlg.ShowDialog();
                if(result == true)
                {
                    client.StopContinuous();
                    selectDeviceInfo.status = model.DeviceStatus.NORMALI;
                    selectDeviceInfo.continuousRunTime = 0;

                    DeviceInfoViewModel info = dlg.windowViewModel.deviceInfo;
                    selectDeviceInfo.step = info.step;
                    selectDeviceInfo.processResult.continuoutDetection = info.processResult.continuoutDetection;

                    DeviceInfo newDevicInfo = new DeviceInfo(selectDeviceInfo);
                    TW_App.deviceInfoCollection.Update(selectDeviceInfo.serialNo, newDevicInfo);
                    TW_App.deviceInfoCollection.Save();

                    btnEnableSetting(selectDeviceInfo.step);

                    if (info.step == ProcessStep.FINISHED)
                    {

                        selectDeviceInfo.status = model.DeviceStatus.FINISH;


                        selectDeviceInfo.testDate = DateTime.Now;
                        RoasterRecord roasterRecord = TW_App.roasterRecordCollection.Find(selectDeviceInfo.serialNo);
                        if (roasterRecord == null)
                        {
                            roasterRecord = new RoasterRecord();
                            roasterRecord.serialNo = selectDeviceInfo.serialNo;
                            roasterRecord.type = selectDeviceInfo.deviceParam.type;
                            roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                            roasterRecord.dateTime = selectDeviceInfo.testDate;
                            TW_App.roasterRecordCollection.Add(roasterRecord);
                        }
                        else
                        {
                            roasterRecord.serialNo = selectDeviceInfo.serialNo;
                            roasterRecord.type = selectDeviceInfo.deviceParam.type;
                            roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                            roasterRecord.dateTime = selectDeviceInfo.testDate;
                            TW_App.roasterRecordCollection.Update(selectDeviceInfo.serialNo, new RoasterRecord(roasterRecord));
                        }
                        TW_App.roasterRecordCollection.Save();
                        DeviceInfo deviceInfo = new DeviceInfo(selectDeviceInfo);
                        deviceInfo.Save(deviceInfo.serialNo);
                        TW_App.globalSetting.Save(deviceInfo.serialNo);
                    }
                }
            }
            else
            {
                MessageBoxResult? result = MessageBox.Show("是否开始烤机检测？检测过程中可以再次单击烤机检测按钮停止检测。", "提示", MessageBoxButton.OKCancel, MessageBoxImage.Question);
                if(result == MessageBoxResult.OK)
                {
                    client.StopContinuous();
                    client.StartContinuousAsync();
                    selectDeviceInfo.status = model.DeviceStatus.RUNNING;
                }
            }
        }

        private void PostSpectrumNoGrating_Click(object sender, RoutedEventArgs e)
        {
            SpectrumTextDlg dlg = new SpectrumTextDlg(selectDeviceInfo);
            dlg.Owner = this;
            dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            bool? result = dlg.ShowDialog();
            if (result == true)
            {
                DeviceInfoViewModel info = dlg.windowViewModel.deviceInfo;
                selectDeviceInfo.step = info.step;
                selectDeviceInfo.processResult.postSpectrumNoGrating = info.processResult.postSpectrumNoGrating;

                DeviceInfo newDevicInfo = new DeviceInfo(selectDeviceInfo);
                TW_App.deviceInfoCollection.Update(selectDeviceInfo.serialNo, newDevicInfo);
                TW_App.deviceInfoCollection.Save();

                btnEnableSetting(selectDeviceInfo.step);
                if (info.step == ProcessStep.FINISHED)
                {

                    selectDeviceInfo.status = model.DeviceStatus.FINISH;


                    selectDeviceInfo.testDate = DateTime.Now;
                    RoasterRecord roasterRecord = TW_App.roasterRecordCollection.Find(selectDeviceInfo.serialNo);
                    if (roasterRecord == null)
                    {
                        roasterRecord = new RoasterRecord();
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Add(roasterRecord);
                    }
                    else
                    {
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Update(selectDeviceInfo.serialNo, new RoasterRecord(roasterRecord));
                    }
                    TW_App.roasterRecordCollection.Save();
                    DeviceInfo deviceInfo = new DeviceInfo(selectDeviceInfo);
                    deviceInfo.Save(deviceInfo.serialNo);
                    TW_App.globalSetting.Save(deviceInfo.serialNo);
                }

            }
        }

        private void PostSpectrumGrating_Cilck(object sender, RoutedEventArgs e)
        {
            SpectrumTextDlg dlg = new SpectrumTextDlg(selectDeviceInfo);
            dlg.Owner = this;
            dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            bool? result = dlg.ShowDialog();
            if (result == true)
            {
                DeviceInfoViewModel info = dlg.windowViewModel.deviceInfo;
                selectDeviceInfo.step = info.step;
                selectDeviceInfo.processResult.postSpectrumGrating = info.processResult.postSpectrumGrating;

                DeviceInfo newDevicInfo = new DeviceInfo(selectDeviceInfo);
                TW_App.deviceInfoCollection.Update(selectDeviceInfo.serialNo, newDevicInfo);
                TW_App.deviceInfoCollection.Save();

                btnEnableSetting(selectDeviceInfo.step);

                if (info.step == ProcessStep.FINISHED)
                {

                    selectDeviceInfo.status = model.DeviceStatus.FINISH;


                    selectDeviceInfo.testDate = DateTime.Now;
                    RoasterRecord roasterRecord = TW_App.roasterRecordCollection.Find(selectDeviceInfo.serialNo);
                    if (roasterRecord == null)
                    {
                        roasterRecord = new RoasterRecord();
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Add(roasterRecord);
                    }
                    else
                    {
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Update(selectDeviceInfo.serialNo, new RoasterRecord(roasterRecord));
                    }
                    TW_App.roasterRecordCollection.Save();
                    DeviceInfo deviceInfo = new DeviceInfo(selectDeviceInfo);
                    deviceInfo.Save(deviceInfo.serialNo);
                    TW_App.globalSetting.Save(deviceInfo.serialNo);
                }
            }
        }

        private void PostEtalonText_Click(object sender, RoutedEventArgs e)
        {
            EtalonTextDlg dlg = new EtalonTextDlg(selectDeviceInfo);
            dlg.Owner = this;
            dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            bool? result = dlg.ShowDialog();
            if (result == true)
            {
                DeviceInfoViewModel info = dlg.windowViewModel.deviceInfo;
                selectDeviceInfo.step = info.step;
                selectDeviceInfo.processResult.postEtalon = info.processResult.postEtalon;

                DeviceInfo newDevicInfo = new DeviceInfo(selectDeviceInfo);
                TW_App.deviceInfoCollection.Update(selectDeviceInfo.serialNo, newDevicInfo);
                TW_App.deviceInfoCollection.Save();

                btnEnableSetting(selectDeviceInfo.step);

                if(info.step == ProcessStep.FINISHED)
                {

                   selectDeviceInfo.status = model.DeviceStatus.FINISH;
                    

                    selectDeviceInfo.testDate = DateTime.Now;
                    RoasterRecord roasterRecord = TW_App.roasterRecordCollection.Find(selectDeviceInfo.serialNo);
                    if(roasterRecord == null)
                    {
                        roasterRecord = new RoasterRecord();
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Add(roasterRecord);
                    }
                    else
                    {
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Update(selectDeviceInfo.serialNo, new RoasterRecord(roasterRecord));
                    }
                    TW_App.roasterRecordCollection.Save();
                    DeviceInfo deviceInfo = new DeviceInfo(selectDeviceInfo);
                    deviceInfo.Save(deviceInfo.serialNo);
                    TW_App.globalSetting.Save(deviceInfo.serialNo);
                }
            }
        }


        private void PostDataAcquisition_Click(object sender, RoutedEventArgs e)
        {
            DataAcquisitionDlg dlg = new DataAcquisitionDlg(selectDeviceInfo);
            dlg.Owner = this;
            dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            bool? result = dlg.ShowDialog();
            if (result == true)
            {
                DeviceInfoViewModel info = dlg.windowViewModel.deviceInfo;
                selectDeviceInfo.step = info.step;
                selectDeviceInfo.processResult.postDataAcquisition = info.processResult.postDataAcquisition;

                DeviceInfo newDevicInfo = new DeviceInfo(selectDeviceInfo);
                TW_App.deviceInfoCollection.Update(selectDeviceInfo.serialNo, newDevicInfo);
                TW_App.deviceInfoCollection.Save();

                btnEnableSetting(selectDeviceInfo.step);

                if (info.step == ProcessStep.FINISHED)
                {

                    selectDeviceInfo.status = model.DeviceStatus.FINISH;


                    selectDeviceInfo.testDate = DateTime.Now;
                    RoasterRecord roasterRecord = TW_App.roasterRecordCollection.Find(selectDeviceInfo.serialNo);
                    if (roasterRecord == null)
                    {
                        roasterRecord = new RoasterRecord();
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Add(roasterRecord);
                    }
                    else
                    {
                        roasterRecord.serialNo = selectDeviceInfo.serialNo;
                        roasterRecord.type = selectDeviceInfo.deviceParam.type;
                        roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                        roasterRecord.dateTime = selectDeviceInfo.testDate;
                        TW_App.roasterRecordCollection.Update(selectDeviceInfo.serialNo, new RoasterRecord(roasterRecord));
                    }
                    TW_App.roasterRecordCollection.Save();
                    DeviceInfo deviceInfo = new DeviceInfo(selectDeviceInfo);
                    deviceInfo.Save(deviceInfo.serialNo);
                    TW_App.globalSetting.Save(deviceInfo.serialNo);
                }
            }
        }

        private void AntiAlarm_Click(object sender, RoutedEventArgs e)
        {
            if (selectDevicePanel == null)
            {
                return;
            }

            if (selectDeviceInfo.status != model.DeviceStatus.ALARM) return;

            DeviceClient client = TW_App.deviceClientManager.Find(selectDevicePanel?.DeviceInfo.serialNo);
            if (client != null && client.dataWorker.isWaveStart)
            {
                if(selectDeviceInfo.continuousRunTime >= TW_App.globalSetting.continuousRunTime)
                {
                    selectDeviceInfo.status = model.DeviceStatus.KJ_FINISH;
                }
                selectDeviceInfo.status = model.DeviceStatus.RUNNING;
            }
            else
            {
                selectDeviceInfo.status = model.DeviceStatus.NORMALI;
            }
        }


        private void AlarmRecord_Click(object sender, RoutedEventArgs e)
        {
            if (selectDeviceInfo == null)
            {
                return;
            }
            AlarmRecordDlg dlg = new AlarmRecordDlg(selectDeviceInfo.serialNo);
            dlg.Owner = this;
            dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            dlg.ShowDialog();
        }


        private void Rollback_Click(object sender, RoutedEventArgs e)
        {
            if (selectDevicePanel == null)
            {
                return;
            }
            string msg = string.Format("序列号为[{0}]的设备将返回上一步检验，是否继续？", selectDevicePanel.DeviceInfo.serialNo);
            MessageBoxResult result = MessageBox.Show(msg, "回退确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
            if (result == MessageBoxResult.No)
            {
                return;
            }
            
            DeviceClient client = TW_App.deviceClientManager.Find(selectDevicePanel?.DeviceInfo.serialNo);
            if (client != null && client.dataWorker.isWaveStart)
            {
                MessageBox.Show("设备正在进行连续烤机，请停止后进行回退操作","提示",MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }


            if (selectDeviceInfo.step == ProcessStep.FINISHED)
            {
                TW_App.roasterRecordCollection.Delete(selectDeviceInfo.serialNo);
                TW_App.roasterRecordCollection.Save();
            }


            //selectDeviceInfo.step--;
            // 查询当前检测步骤
            if(selectDeviceInfo.step == ProcessStep.FINISHED)
            {
                selectDeviceInfo.step = (ProcessStep)TW_App.globalSetting.inspectionSequences[TW_App.globalSetting.inspectionSequences.Count-1];
            }
            else
            {
                int index = TW_App.globalSetting.inspectionSequences.IndexOf((int)selectDeviceInfo.step);
                if (index == -1)
                {
                    MessageBox.Show("当前处于未知检测项，请联系系统管理员", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }

                selectDeviceInfo.step = (ProcessStep)TW_App.globalSetting.inspectionSequences[index - 1];
            }

            

            selectDeviceInfo.status = model.DeviceStatus.NORMALI;


            TW_App.deviceInfoCollection.Update(selectDeviceInfo.serialNo, new DeviceInfo(selectDeviceInfo));
            TW_App.deviceInfoCollection.Save();
            //windowViewModel.Reload();

            btnEnableSetting(selectDeviceInfo.step);
        }

        private void ReText_Click(object sender, RoutedEventArgs e)
        {

            if (selectDevicePanel == null)
            {
                return;
            }
            string msg = string.Format("序列号为[{0}]的设备将返回重新检验，是否继续？", selectDevicePanel.DeviceInfo.serialNo);
            MessageBoxResult result = MessageBox.Show(msg, "重检确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
            if (result == MessageBoxResult.No)
            {
                return;
            }

            DeviceClient client = TW_App.deviceClientManager.Find(selectDevicePanel?.DeviceInfo.serialNo);
            if (client != null && client.dataWorker.isWaveStart)
            {
                MessageBox.Show("设备正在进行连续烤机，请停止后进行回退操作", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
                return;
            }

            if(selectDeviceInfo.step == ProcessStep.FINISHED)
            {
                TW_App.roasterRecordCollection.Delete(selectDeviceInfo.serialNo);
                TW_App.roasterRecordCollection.Save();
            }

            //selectDeviceInfo.step = ProcessStep.PRE_ETALON;
            selectDeviceInfo.step = (ProcessStep)TW_App.globalSetting.inspectionSequences[0];
            selectDeviceInfo.status = model.DeviceStatus.NORMALI;
            selectDeviceInfo.maxContinuousRunTime = 0;
            selectDeviceInfo.continuousRunTime = 0;

            TW_App.deviceInfoCollection.Update(selectDeviceInfo.serialNo, new DeviceInfo(selectDeviceInfo));
            TW_App.deviceInfoCollection.Save();
            //windowViewModel.Reload();

            btnEnableSetting(selectDeviceInfo.step);
        }


        private void Finished_Click(object sender, RoutedEventArgs e)
        {
            if(selectDeviceInfo == null)
            {
                return;
            }

            DeviceClient client = TW_App.deviceClientManager.Find(selectDevicePanel?.DeviceInfo.serialNo);
            if (client != null)
            {
                client.Stop();
                client.Join();
            }
            TW_App.deviceClientManager.Delete(selectDevicePanel?.DeviceInfo.serialNo);

            selectDevicePanel.MouseLeftButtonDown -= DevicePanel_MouseLeftButtonDown;
            wpDevicePanel.Children.Remove(selectDevicePanel);

            RoasterRecord roasterRecord = TW_App.roasterRecordCollection.Find(selectDeviceInfo.serialNo);
            if (roasterRecord == null)
            {
                roasterRecord = new RoasterRecord();
                roasterRecord.serialNo = selectDeviceInfo.serialNo;
                roasterRecord.type = selectDeviceInfo.deviceParam.type;
                roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                roasterRecord.dateTime = selectDeviceInfo.testDate;
                TW_App.roasterRecordCollection.Add(roasterRecord);
            }
            else
            {
                roasterRecord.serialNo = selectDeviceInfo.serialNo;
                roasterRecord.type = selectDeviceInfo.deviceParam.type;
                roasterRecord.channelNum = selectDeviceInfo.deviceParam.nChannel;
                roasterRecord.dateTime = selectDeviceInfo.testDate;
                TW_App.roasterRecordCollection.Update(selectDeviceInfo.serialNo, new RoasterRecord(roasterRecord));
            }
            TW_App.roasterRecordCollection.Save();
            DeviceInfo deviceInfo = new DeviceInfo(selectDeviceInfo);
            deviceInfo.Save(deviceInfo.serialNo);

            TW_App.deviceInfoCollection.Delete(selectDevicePanel.DeviceInfo.serialNo);
            TW_App.deviceInfoCollection.Save();

            windowViewModel.deviceInfos.Remove(selectDeviceInfo);

            selectDevicePanel = null;
            selectDeviceInfo = null;
        }

        private void CreateReport_Click(object sender, RoutedEventArgs e)
        {
            if (selectDeviceInfo == null)
            {
                return;
            }

            SaveFileDialog saveFileDialog = new SaveFileDialog();

            // 设置文件过滤器
            saveFileDialog.Filter = "Word 文档 (*.docx)|*.docx";

            // 设置默认文件名
            saveFileDialog.FileName = selectDeviceInfo.deviceParam.type+"-出厂检验报告.docx";

            // 设置对话框标题
            saveFileDialog.Title = "生成检验报告";

            // 显示保存文件对话框
            bool? result = saveFileDialog.ShowDialog();

            // 检查用户是否点击了保存按钮
            if (result == true)
            {
                // 获取用户选择的文件路径
                string filePath = saveFileDialog.FileName;

                CreateReport.Create(filePath,new DeviceInfo(selectDeviceInfo));
            }
        }

        private void RoasterRecord_Click(object sender, RoutedEventArgs e)
        {
            RoasterRecordDlg dlg = new RoasterRecordDlg();
            dlg.Owner = this;
            dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            dlg.ShowDialog();
        }

        private void ToolBar_Loaded(object sender, RoutedEventArgs e)
        {
            //去掉ToolBar右边默认的扩展图标
            ToolBar toolBar = sender as ToolBar;

            var overflowGrid = toolBar.Template.FindName("OverflowGrid", toolBar) as FrameworkElement;

            if (overflowGrid != null)
            {
                overflowGrid.Visibility = Visibility.Collapsed;
            }
            var mainPanelBorder = toolBar.Template.FindName("MainPanelBorder", toolBar) as FrameworkElement;

            if (mainPanelBorder != null)
            {
                mainPanelBorder.Margin = new Thickness(0);
            }
        }
        #endregion

        #region 方法
        private DateTime tm1 = DateTime.Now;
        Dictionary<int, SpectrumPkgBuffer> selectedSpectrumDic = new Dictionary<int, SpectrumPkgBuffer>();
        Dictionary<int, SpectrumPkgBuffer> spectrumRecvBufferDic = new Dictionary<int, SpectrumPkgBuffer>();

        private void InitChart()
        {
            LoadSpectrumSetting();

            chartRefreshMsgWorker = CreateChartRefreshWorker();
            peaksRefreshMsgWorker = CreatePeaksRefreshWorker();
        }

        #region 光谱接收
        private OPM_MsgWorker CreateChartRefreshWorker()
        {
            OPM_MsgWorker worker = new OPM_MsgWorker();
            worker.handleProc = ChartDataRefreshProc;

            QueueDataType key = QueueDataType.DATA_SP;
            worker.keyList.Add(key);

            return worker;
        }

        private void StartChartRefreshWorker()
        {
            if (chartRefreshMsgWorker.IsStop())
            {
                chartRefreshMsgWorker.StartAsync();

                selectedSpectrumDic.Clear();
                List<QueueDataType> keyList = new List<QueueDataType>();
                QueueDataType key = QueueDataType.DATA_SP;
                keyList.Add(key);

                if(windowViewModel.spectrumDisplayViewModel.selectedChannelItem != null)
                {
                    int channelNo = windowViewModel.spectrumDisplayViewModel.selectedChannelItem.no;

                    SpectrumPkgBuffer pkgBuffer = new SpectrumPkgBuffer();
                    pkgBuffer.channelNo = channelNo;
                    selectedSpectrumDic.Add(channelNo, pkgBuffer);
                }

                chartRefreshMsgWorker.keyList = keyList;
                DeviceClient client = TW_App.deviceClientManager.Find(selectDeviceInfo?.serialNo);
                if(client != null)
                {
                    client.Register(chartRefreshMsgWorker, chartRefreshMsgWorker.keyList);
                }
            }
        }

        private void StopChartRefreshWorker()
        {
            if (!chartRefreshMsgWorker.IsStop())
            {
                chartRefreshMsgWorker.Stop();

                List<QueueDataType> keyList = new List<QueueDataType>(); 
                QueueDataType key = QueueDataType.DATA_SP; 
                keyList.Add(key);

                DeviceClient client = TW_App.deviceClientManager.Find(selectDeviceInfo?.serialNo);
                if (client != null)
                {
                    client.UnRegister(chartRefreshMsgWorker, keyList);
                }

                logger.InfoFormat("光谱图更新线程停止");
            }
        }

        private void JoinChartRefreshWorker()
        {
            if (chartRefreshMsgWorker.IsStop())
            {
                chartRefreshMsgWorker.Join();
            }
        }

        private void RegisterChartRefreshWorker()
        {
            if (selectDeviceInfo != null)
            {
                DeviceClient client = TW_App.deviceClientManager.Find(selectDeviceInfo?.serialNo);
                if (client != null)
                {
                    List<QueueDataType> keyList = new List<QueueDataType>();
                    QueueDataType key = QueueDataType.DATA_SP;
                    keyList.Add(key);
                    client.Register(chartRefreshMsgWorker, chartRefreshMsgWorker.keyList);
                }
            }
        }

        private void UnRegisterChartRefreshWorker()
        {
            if (selectDeviceInfo != null)
            {
                List<QueueDataType> keyList = new List<QueueDataType>();
                QueueDataType key = QueueDataType.DATA_SP;
                keyList.Add(key);
                DeviceClient client = TW_App.deviceClientManager.Find(selectDeviceInfo?.serialNo);
                if (client != null)
                {
                    client.UnRegister(chartRefreshMsgWorker, chartRefreshMsgWorker.keyList);
                }
            }
        }

        private void ChartDataRefreshProc(QueueData msg) // UDP
        {
            lock (gsLocker)
            {
                SpectrumAcqData spData = ((SpectrumZData)msg).spectrumData;
                if (selectedSpectrumDic.ContainsKey(spData.channelNo)) 
                {
                    if (!spectrumRecvBufferDic.ContainsKey(spData.channelNo)) 
                    {
                        spectrumRecvBufferDic.Add(spData.channelNo, new SpectrumPkgBuffer()); 
                    }

                    SpectrumPkgBuffer pkgBuffer = spectrumRecvBufferDic[spData.channelNo];
                    int rn = pkgBuffer.Add(spData);
                    if (rn != 0)
                    {
                        logger.ErrorFormat("通道({0})的光谱插入数据时失败,buffer重置,rn={1}", spData.channelNo, rn);
                        pkgBuffer.Clear();
                        pkgBuffer.Add(spData);//重置后保留新数据
                        return;
                    }
                    else
                    {
                        if (pkgBuffer.isFull())
                        {
                            //从临时区中移除
                            spectrumRecvBufferDic.Remove(spData.channelNo);
                            spectrumRecvBufferDic.Add(spData.channelNo, new SpectrumPkgBuffer());

                            logger.DebugFormat("channel({0}) data is ready to show", spData.channelNo);

                            //添加到显示区中
                            if (selectedSpectrumDic.ContainsKey(spData.channelNo))
                            {
                                selectedSpectrumDic.Remove(spData.channelNo);
                            }
                            selectedSpectrumDic.Add(spData.channelNo, pkgBuffer);
                        }
                    }
                }
                else
                {
                    return;
                }


            }
        }
        #endregion

        #region 波长接收

        List<ValuePoint> waveLenLine = new List<ValuePoint>();
        private uint nextSeq = 0;

        private OPM_MsgWorker CreatePeaksRefreshWorker()
        {
            OPM_MsgWorker worker = new OPM_MsgWorker();
            worker.handleProc = PeaksDataRefreshProc;
            worker.keyList.Add(QueueDataType.DATA_WL);

            return worker;
        }

        private void StartPeaksRefreshWorker()
        {
            if (peaksRefreshMsgWorker.IsStop())
            {
                DeviceClient client = TW_App.deviceClientManager.Find(selectDeviceInfo?.serialNo);
                if(client != null)
                {
                    client.Register(peaksRefreshMsgWorker, QueueDataType.DATA_WL);
                }
                peaksRefreshMsgWorker.StartAsync();
            }
        }

        private void StopPeaksRefreshWorker()
        {
            if (!peaksRefreshMsgWorker.IsStop())
            {
                peaksRefreshMsgWorker.Stop();
                DeviceClient client = TW_App.deviceClientManager.Find(selectDeviceInfo?.serialNo);
                if (client != null)
                {
                    client.UnRegister(peaksRefreshMsgWorker, QueueDataType.DATA_WL);
                }

                logger.DebugFormat("Peaks发现更新线程结束");
            }
        }

        private void JoinPeaksRefreshWorker()
        {
            if (peaksRefreshMsgWorker.IsStop())
            {
                peaksRefreshMsgWorker.Join();
            }
        }

        private void RegisterPeaksRefreshWorker()
        {
            if(selectDeviceInfo != null)
            {
                DeviceClient client = TW_App.deviceClientManager.Find(selectDeviceInfo?.serialNo);
                if (client != null)
                {
                    client.Register(peaksRefreshMsgWorker, QueueDataType.DATA_WL);
                }
            }
        }
        private void UnRegisterPeaksRefreshWorker()
        {
            if (selectDeviceInfo != null)
            {
                DeviceClient client = TW_App.deviceClientManager.Find(selectDeviceInfo?.serialNo);
                if (client != null)
                {
                    client.UnRegister(peaksRefreshMsgWorker, QueueDataType.DATA_WL);
                }
            }
        }


        private void PeaksDataRefreshProc(QueueData msg)
        {
            //发现peaks锁
            lock (peaksLocker)
            {
                bool showFlag = false;
                DateTime tm2 = DateTime.Now;
                TimeSpan ts = tm2 - tm1;

                int frequence = 10;
                int intervalTm = 1000 / frequence;

                if (ts.TotalMilliseconds > intervalTm)
                {
                    showFlag = true;
                    tm1 = DateTime.Now;
                }

                if (showFlag)
                {
                    Wave waveLenData = (Wave)msg;

                    int channelNo = windowViewModel.spectrumDisplayViewModel.selectedChannelItem.no;
                    int grattingNo = windowViewModel.waveLenDisplaySetting.selectedGrattingNo.no;
                    int dataCounts = (int)windowViewModel.waveLenDisplaySetting.valueRangeX.maxValue;
                    nextSeq++;

                    FillLineData(waveLenLine, msg, channelNo,grattingNo,dataCounts);
                    if (showFlag)
                    {
                        //Console.WriteLine("ShowData 1 --- tm:{0}, seq:{1}, counts:{2}", DateTime.Now.ToString("yyyyMMddHHmmssfff"), nextSeq, chartRefreshMsgWorker.recvQueue.GetCounts());
                        App.Current.Dispatcher.InvokeAsync((Action)(() =>
                        {
                            ShowWaveLenData(waveLenLine,dataCounts);
                        }));
                    }
                }

            }
        }

        private void ShowWaveLenData(List<ValuePoint> lines, int dataCounts)
        {
            lock (gsLocker)
            {
                List<List<ValuePoint>> lineList = new List<List<ValuePoint>>();
                lineList.Add(lines);


                //设置DataWnd
                DataWnd dataWnd = new DataWnd(lineChartWaveLen.axisScaleWindow.dataWnd);


                //X轴范围

                dataWnd.valueRangeX.maxValue = nextSeq;
                double minValue = nextSeq - dataCounts;
                if (minValue < 0) minValue = 0;
                dataWnd.valueRangeX.minValue = minValue;
                

                lineChartWaveLen.ResetX(dataWnd.valueRangeX);
                lineChartWaveLen.elemList = lineList;


                //Y轴范围

                ValueRangeViewModel valueRangeY = new ValueRangeViewModel();

                if (lines.Count > 0)
                {
                    valueRangeY.minValue = lines[0].valY;
                    valueRangeY.maxValue = lines[0].valY;
                }
                

                //全部都是空
                if (valueRangeY.minValue.Equals(double.NaN) || valueRangeY.maxValue.Equals(double.NaN))
                {
                    return;
                }


                foreach (var point in lines)
                {
                    if (point.valY < valueRangeY.minValue)
                    {
                        valueRangeY.minValue = point.valY;
                    }
                    else if (point.valY > valueRangeY.maxValue)
                    {
                        valueRangeY.maxValue = point.valY;
                    }
                }
                

                double diffValue = valueRangeY.maxValue - valueRangeY.minValue;
                if (diffValue < 0.02) diffValue = 0.02;
                dataWnd.valueRangeY.minValue = valueRangeY.minValue - diffValue * 0.25;
                dataWnd.valueRangeY.maxValue = valueRangeY.maxValue + diffValue * 0.25;

                windowViewModel.waveLenDisplaySetting.valueRangeY.minValue = dataWnd.valueRangeY.minValue;
                windowViewModel.waveLenDisplaySetting.valueRangeY.maxValue = dataWnd.valueRangeY.maxValue;

                lineChartWaveLen.ResetY(dataWnd.valueRangeY);


                System.Drawing.Pen borderPen = new System.Drawing.Pen(System.Drawing.Color.Black, 1);
                

                ColorLegend colorLegend = MakeWaveLenLegend(windowViewModel.spectrumDisplayViewModel.selectedChannelItem.no, windowViewModel.waveLenDisplaySetting.selectedGrattingNo.no, new Font("Arial", 8), borderPen);
                lineChartWaveLen.colorLegend = colorLegend;
                lineChartWaveLen.Show(true);


                //显示当前值

                double currentValue = double.NaN;
                if (lines.Count > 0)
                {
                    currentValue = lines.Last().valY;
                }
                    
                
                windowViewModel.waveLenCurrentValue = currentValue;

            }

        }

        //newData.text = string.Format("光栅{0}-{1}", v.channelNo, v.grattingNo);
        private ColorLegend MakeWaveLenLegend(int channelNo,int grattingNo, Font font, System.Drawing.Pen borderPen)
        {
            List<ColorLegendData> colorLegendDataList = new List<ColorLegendData>();

            ColorLegendData newData = new ColorLegendData();
            newData.color = chSeriesColor[0];
            newData.text = string.Format("光栅{0}-{1}", channelNo, grattingNo);

            colorLegendDataList.Add(newData);
            
            ColorLegend colorLegend = new ColorLegend(colorLegendDataList, font, borderPen, Position.TopRight);
            return colorLegend;

        }

        private void FillLineData(List<ValuePoint> line, QueueData msg, int channelNo, int grattingNo, int dataCounts) // UDP
        {
            if (msg.type != QueueDataType.DATA_WL)
            {
                logger.ErrorFormat("收到不支持的消息类型（{0:x8}）", msg.type);
                return;
            }
            Wave waveLenData = (Wave)msg;


            //if (waveLenData.nChannel < channelNo || waveLenData.wave[channelNo - 1].ngratting < grattingNo) // TCP
            if (waveLenData.nChannel < channelNo || waveLenData.chGratting[channelNo - 1].ngrating < grattingNo) // UDP
            {
                logger.ErrorFormat("设置的通道数({0}/{1})不正确)", waveLenData.nChannel, channelNo);
                return;
            }

            //if (waveLenData.wave[channelNo - 1].ngratting < grattingNo) // TCP
            if (waveLenData.chGratting[channelNo - 1].ngrating < grattingNo) // UDP
            {
                //logger.ErrorFormat("设置的光栅数({0}/{1})不正确)", waveLenData.wave[channelNo - 1].ngratting, grattingNo); // TCP
                logger.ErrorFormat("设置的光栅数({0}/{1})不正确)", waveLenData.chGratting[channelNo - 1].ngrating, grattingNo); // UDP
            return;
            }

            //double val = waveLenData.wave[channelNo - 1].waveLen[grattingNo - 1]; // TCP
            double val = waveLenData.chGratting[channelNo - 1].waveValueArray[grattingNo - 1]; // UDP
            line.Add(new ValuePoint(nextSeq, val));
            if (line.Count > dataCounts)
            {
                line.RemoveAt(0); //删除第一个
            }
            
        }
        #endregion

        #region 光谱显示刷新
        private void TimerThreadProc()
        {
            while (!timerThreadStopFlag)
            {
                int frequence = 2;
                int intervalTm = 1000 / frequence;

                App.Current?.Dispatcher.InvokeAsync((Action)(() =>
                {
                    lock (gsLocker)
                    {
                        //光谱停止时，停止刷新
                        if (selectedSpectrumDic.Count() == 0) return;

                        List<SpectrumPkgBuffer> sortFullSpData = selectedSpectrumDic.Values.OrderBy(x => x.channelNo).ToList();

                        ShowSpectrumData(sortFullSpData);
                    }
                }));

                Thread.Sleep(intervalTm);
            }
        }

        private void ShowSpectrumData(List<SpectrumPkgBuffer> spDataList) 
        {
            if (lineChartSpectrum.elemList == null)
            {
                lineChartSpectrum.elemList = new List<List<ValuePoint>>();
            }

            lineChartSpectrum.elemList.Clear();

            ValueRange valueRangeX = new ValueRange();

            //设置数据
            foreach (var data in spDataList)
            {
                List<ValuePoint> valuePoints = new List<ValuePoint>();

                //有可能接收的数据是不按照顺序的，需要排序后保证波长从小到大的顺序
                List<SpectrumAcqData> sortSubData = data.GetData().OrderBy(x => x.subPkgNo).ToList(); 
                foreach (var subData in sortSubData) 
                {  
                    for (int i = 0; i < subData.counts; i++) 
                    {
                        double valX = subData.startWaveLen + i * (subData.interval / 1000.0); 
                        double valY = subData.data[i]; 

                        valuePoints.Add(new ValuePoint(valX, valY));

                        if (double.IsNaN(valueRangeX.minValue))
                        {
                            valueRangeX.minValue = valX;
                        }
                        else if (valX < valueRangeX.minValue)
                        {
                            valueRangeX.minValue = valX;
                        }

                        if (double.IsNaN(valueRangeX.maxValue))
                        {
                            valueRangeX.maxValue = valX;
                        }
                        else if (valX > valueRangeX.maxValue)
                        {
                            valueRangeX.maxValue = valX;
                        }
                    }
                }

                lineChartSpectrum.elemList.Add(valuePoints);
            }


            lineChartSpectrum.axisScaleWindow.scaleX.valueRange.minValue = valueRangeX.minValue;
            lineChartSpectrum.axisScaleWindow.scaleX.valueRange.maxValue = valueRangeX.maxValue;
            windowViewModel.spectrumDisplayViewModel.waveLenRange.minValue = valueRangeX.minValue;
            windowViewModel.spectrumDisplayViewModel.waveLenRange.maxValue = valueRangeX.maxValue;
            

            //设置图例
            List<ColorLegendData> colorLegendDataList = new List<ColorLegendData>();

            for (int i = 0; i < spDataList.Count; i++)
            {
                ColorLegendData newData = new ColorLegendData();
                newData.color = chSeriesColor[i];

                newData.text = "通道" + spDataList[i].channelNo; 

                
                colorLegendDataList.Add(newData);
            }

            System.Drawing.Pen borderPen = new System.Drawing.Pen(System.Drawing.Color.Black, 1);
            ColorLegend colorLegend = new ColorLegend(colorLegendDataList, new Font("Arial", 8), borderPen, Position.TopRight);

            lineChartSpectrum.colorLegend = colorLegend;

            lineChartSpectrum.Show(true);
        }
        #endregion

        private void ReadSpectrum()
        {
            if(selectDeviceInfo == null)
            {
                return;
            }
            DeviceClient client = TW_App.deviceClientManager.Find(selectDeviceInfo?.serialNo);
            if (client == null) return;

            if (client.dataWorker.ssResp == null || client.dataWorker.ssResp.channelNum == 0)
            {
                client.dataWorker.GetSpectrumSummary();
            }

            ChannelItemViewModel channelItemViewModel = windowViewModel.spectrumDisplayViewModel.selectedChannelItem;
            try
            {
                new Thread(() => client.dataWorker.ReadSpectrum(channelItemViewModel)).Start();
            }
            catch (Exception)
            {
            }
        }

        private ChannelParameter CreateChannelSettingItem()
        {
            ChannelParameter item = new ChannelParameter();
            item.chID = (char)windowViewModel.spectrumDisplayViewModel.selectedChannelItem.no;
            item.threshold = (int)(windowViewModel.chParamViewModel.threshold * 100);
            item.refThreshold = (int)(windowViewModel.chParamViewModel.refThreshold * 100);
            item.width = (int)(windowViewModel.chParamViewModel.width * 100);
            item.widthLevel = (int)(windowViewModel.chParamViewModel.widthLevel * 100);

            return item;
        }


        private void btnEnableSetting(ProcessStep step)
        {
            switch (step)
            {
                case ProcessStep.NOT_STARTED:
                    toolPreDataAcquisition.IsEnabled = false;
                    toolPostDataAcquisition.IsEnabled = false;
                    toolPreEtalonText.IsEnabled = false;
                    toolPreSpectrumGrating.IsEnabled = false;
                    toolPreSpectrumNoGrating.IsEnabled = false;
                    toolContinuousDetection.IsEnabled = false;
                    toolPostSpectrumNoGrating.IsEnabled = false;
                    toolPostSpectrumGrating.IsEnabled = false;
                    toolPostEtalonText.IsEnabled = false;
                    toolCreateReport.IsEnabled = false;
                    toolRollback.IsEnabled = false;
                    toolReText.IsEnabled = false;
                    toolFinished.IsEnabled = false;
                    break;
                case ProcessStep.PRE_DATA_ACQUISITION:
                    toolPreDataAcquisition.IsEnabled = true;
                    toolPostDataAcquisition.IsEnabled = false;
                    toolPreEtalonText.IsEnabled = false;
                    toolPreSpectrumGrating.IsEnabled = false;
                    toolPreSpectrumNoGrating.IsEnabled = false;
                    toolContinuousDetection.IsEnabled = false;
                    toolPostSpectrumNoGrating.IsEnabled = false;
                    toolPostSpectrumGrating.IsEnabled = false;
                    toolPostEtalonText.IsEnabled = false;
                    toolCreateReport.IsEnabled = false;
                    if (TW_App.globalSetting.inspectionSequences[0] == (int)ProcessStep.PRE_ETALON)
                    {
                        toolRollback.IsEnabled = false;
                        toolReText.IsEnabled = false;
                    }
                    else
                    {
                        toolRollback.IsEnabled = true;
                        toolReText.IsEnabled = true;
                    }

                    toolFinished.IsEnabled = false;
                    break;
                case ProcessStep.PRE_ETALON:
                    toolPreDataAcquisition.IsEnabled = false;
                    toolPostDataAcquisition.IsEnabled = false;
                    toolPreEtalonText.IsEnabled = true;
                    toolPreSpectrumGrating.IsEnabled = false;
                    toolPreSpectrumNoGrating.IsEnabled = false;
                    toolContinuousDetection.IsEnabled = false;
                    toolPostSpectrumNoGrating.IsEnabled = false;
                    toolPostSpectrumGrating.IsEnabled = false;
                    toolPostEtalonText.IsEnabled = false;
                    toolCreateReport.IsEnabled = false;
                    if (TW_App.globalSetting.inspectionSequences[0] == (int)ProcessStep.PRE_ETALON)
                    {
                        toolRollback.IsEnabled = false;
                        toolReText.IsEnabled = false;
                    }
                    else
                    {
                        toolRollback.IsEnabled = true;
                        toolReText.IsEnabled = true;
                    }

                    toolFinished.IsEnabled = false;
                    break;
                case ProcessStep.PRE_SPECTRUM_GRATING:
                    toolPreDataAcquisition.IsEnabled = false;
                    toolPostDataAcquisition.IsEnabled = false;
                    toolPreEtalonText.IsEnabled = false;
                    toolPreSpectrumGrating.IsEnabled = true;
                    toolPreSpectrumNoGrating.IsEnabled = false;
                    toolContinuousDetection.IsEnabled = false;
                    toolPostSpectrumNoGrating.IsEnabled = false;
                    toolPostSpectrumGrating.IsEnabled = false;
                    toolPostEtalonText.IsEnabled = false;
                    toolCreateReport.IsEnabled = false;
                    if (TW_App.globalSetting.inspectionSequences[0] == (int)ProcessStep.PRE_SPECTRUM_GRATING)
                    {
                        toolRollback.IsEnabled = false;
                        toolReText.IsEnabled = false;
                    }
                    else
                    {
                        toolRollback.IsEnabled = true;
                        toolReText.IsEnabled = true;
                    }
                    toolFinished.IsEnabled = false;
                    break;
                case ProcessStep.PRE_SPECTRUM_NO_GRATING:
                    toolPreDataAcquisition.IsEnabled = false;
                    toolPostDataAcquisition.IsEnabled = false;
                    toolPreEtalonText.IsEnabled = false;
                    toolPreSpectrumGrating.IsEnabled = false;
                    toolPreSpectrumNoGrating.IsEnabled = true;
                    toolContinuousDetection.IsEnabled = false;
                    toolPostSpectrumNoGrating.IsEnabled = false;
                    toolPostSpectrumGrating.IsEnabled = false;
                    toolPostEtalonText.IsEnabled = false;
                    toolCreateReport.IsEnabled = false;
                    if (TW_App.globalSetting.inspectionSequences[0] == (int)ProcessStep.PRE_SPECTRUM_NO_GRATING)
                    {
                        toolRollback.IsEnabled = false;
                        toolReText.IsEnabled = false;
                    }
                    else
                    {
                        toolRollback.IsEnabled = true;
                        toolReText.IsEnabled = true;
                    }
                    toolFinished.IsEnabled = false;
                    break;
                case ProcessStep.CONTINUOUS_DETECTION:
                    toolPreDataAcquisition.IsEnabled = false;
                    toolPostDataAcquisition.IsEnabled = false;
                    toolPreEtalonText.IsEnabled = false;
                    toolPreSpectrumGrating.IsEnabled = false;
                    toolPreSpectrumNoGrating.IsEnabled = false;
                    toolContinuousDetection.IsEnabled = true;
                    toolPostSpectrumNoGrating.IsEnabled = false;
                    toolPostSpectrumGrating.IsEnabled = false;
                    toolPostEtalonText.IsEnabled = false;
                    toolCreateReport.IsEnabled = false;
                    if (TW_App.globalSetting.inspectionSequences[0] == (int)ProcessStep.CONTINUOUS_DETECTION)
                    {
                        toolRollback.IsEnabled = false;
                        toolReText.IsEnabled = false;
                    }
                    else
                    {
                        toolRollback.IsEnabled = true;
                        toolReText.IsEnabled = true;
                    }
                    toolFinished.IsEnabled = false;
                    break;
                case ProcessStep.POST_SPECTRUM_NO_GRATING:
                    toolPreDataAcquisition.IsEnabled = false;
                    toolPostDataAcquisition.IsEnabled = false;
                    toolPreEtalonText.IsEnabled = false;
                    toolPreSpectrumGrating.IsEnabled = false;
                    toolPreSpectrumNoGrating.IsEnabled = false;
                    toolContinuousDetection.IsEnabled = false;
                    toolPostSpectrumNoGrating.IsEnabled = true;
                    toolPostSpectrumGrating.IsEnabled = false;
                    toolPostEtalonText.IsEnabled = false;
                    toolCreateReport.IsEnabled = false;
                    if (TW_App.globalSetting.inspectionSequences[0] == (int)ProcessStep.POST_SPECTRUM_NO_GRATING)
                    {
                        toolRollback.IsEnabled = false;
                        toolReText.IsEnabled = false;
                    }
                    else
                    {
                        toolRollback.IsEnabled = true;
                        toolReText.IsEnabled = true;
                    }
                    toolFinished.IsEnabled = false;
                    break;
                case ProcessStep.POST_SPECTRUM_GRATING:
                    toolPreDataAcquisition.IsEnabled = false;
                    toolPostDataAcquisition.IsEnabled = false;
                    toolPreEtalonText.IsEnabled = false;
                    toolPreSpectrumGrating.IsEnabled = false;
                    toolPreSpectrumNoGrating.IsEnabled = false;
                    toolContinuousDetection.IsEnabled = false;
                    toolPostSpectrumNoGrating.IsEnabled = false;
                    toolPostSpectrumGrating.IsEnabled = true;
                    toolPostEtalonText.IsEnabled = false;
                    toolCreateReport.IsEnabled = false;
                    if (TW_App.globalSetting.inspectionSequences[0] == (int)ProcessStep.POST_SPECTRUM_GRATING)
                    {
                        toolRollback.IsEnabled = false;
                        toolReText.IsEnabled = false;
                    }
                    else
                    {
                        toolRollback.IsEnabled = true;
                        toolReText.IsEnabled = true;
                    }
                    toolFinished.IsEnabled = false;
                    break;
                case ProcessStep.POST_ETALON:
                    toolPreDataAcquisition.IsEnabled = false;
                    toolPostDataAcquisition.IsEnabled = false;
                    toolPreEtalonText.IsEnabled = false;
                    toolPreSpectrumGrating.IsEnabled = false;
                    toolPreSpectrumNoGrating.IsEnabled = false;
                    toolContinuousDetection.IsEnabled = false;
                    toolPostSpectrumNoGrating.IsEnabled = false;
                    toolPostSpectrumGrating.IsEnabled = false;
                    toolPostEtalonText.IsEnabled = true;
                    toolCreateReport.IsEnabled = false;
                    if (TW_App.globalSetting.inspectionSequences[0] == (int)ProcessStep.POST_ETALON)
                    {
                        toolRollback.IsEnabled = false;
                        toolReText.IsEnabled = false;
                    }
                    else
                    {
                        toolRollback.IsEnabled = true;
                        toolReText.IsEnabled = true;
                    }
                    toolFinished.IsEnabled = false;
                    break;
                case ProcessStep.POST_DATA_ACQUISITION:
                    toolPreDataAcquisition.IsEnabled = false;
                    toolPostDataAcquisition.IsEnabled = true;
                    toolPreEtalonText.IsEnabled = false;
                    toolPreSpectrumGrating.IsEnabled = false;
                    toolPreSpectrumNoGrating.IsEnabled = false;
                    toolContinuousDetection.IsEnabled = false;
                    toolPostSpectrumNoGrating.IsEnabled = false;
                    toolPostSpectrumGrating.IsEnabled = false;
                    toolPostEtalonText.IsEnabled = false;
                    toolCreateReport.IsEnabled = false;
                    if (TW_App.globalSetting.inspectionSequences[0] == (int)ProcessStep.POST_ETALON)
                    {
                        toolRollback.IsEnabled = false;
                        toolReText.IsEnabled = false;
                    }
                    else
                    {
                        toolRollback.IsEnabled = true;
                        toolReText.IsEnabled = true;
                    }
                    toolFinished.IsEnabled = false;
                    break;
                case ProcessStep.FINISHED:
                    toolPreDataAcquisition.IsEnabled = false;
                    toolPostDataAcquisition.IsEnabled = false;
                    toolPreEtalonText.IsEnabled = false;
                    toolPreSpectrumGrating.IsEnabled = false;
                    toolPreSpectrumNoGrating.IsEnabled = false;
                    toolContinuousDetection.IsEnabled = false;
                    toolPostSpectrumNoGrating.IsEnabled = false;
                    toolPostSpectrumGrating.IsEnabled = false;
                    toolPostEtalonText.IsEnabled = false;
                    toolCreateReport.IsEnabled = true;
                    toolRollback.IsEnabled = true;
                    toolReText.IsEnabled = true;
                    toolFinished.IsEnabled = true;
                    break;
                default:
                    toolPreDataAcquisition.IsEnabled = false;
                    toolPostDataAcquisition.IsEnabled = false;
                    toolPreEtalonText.IsEnabled = false;
                    toolPreSpectrumGrating.IsEnabled = false;
                    toolPreSpectrumNoGrating.IsEnabled = false;
                    toolContinuousDetection.IsEnabled = false;
                    toolPostSpectrumNoGrating.IsEnabled = false;
                    toolPostSpectrumGrating.IsEnabled = false;
                    toolPostEtalonText.IsEnabled = false;
                    toolCreateReport.IsEnabled = false;
                    toolRollback.IsEnabled = false;
                    toolReText.IsEnabled = false;
                    toolFinished.IsEnabled = false;
                    break;
            }
        }
        #endregion


        #region 光谱相关
        List<System.Drawing.Color> chSeriesColor;
        LineChart lineChartSpectrum = null;

        private int LoadSpectrumSetting()
        {
            int rn = 0;
            try
            {
                if(selectDevicePanel == null)
                {
                    SpectrumDisplayViewModel displayViewModel = windowViewModel.spectrumDisplayViewModel;

                    displayViewModel.waveLenRange = new ValueRangeViewModel();
                    displayViewModel.waveLenRange.minValue = 1510;
                    displayViewModel.waveLenRange.maxValue = 1590;

                    displayViewModel.dBmRange = new ValueRangeViewModel();
                    displayViewModel.dBmRange.minValue = -75;
                    displayViewModel.dBmRange.maxValue = 0;

                    ObservableCollection<double> refLines = new ObservableCollection<double>();
                    displayViewModel.referenceLines = refLines;
                }
                else
                {
                    SpectrumDisplayViewModel displayViewModel = windowViewModel.spectrumDisplayViewModel;

                    displayViewModel.waveLenRange.minValue = 1510;
                    displayViewModel.waveLenRange.maxValue = 1590;

                    displayViewModel.dBmRange.minValue = -65;
                    displayViewModel.dBmRange.maxValue = 0;
                }
            }
            catch(Exception ex)
            {
                logger.ErrorFormat("光谱页面设置加载异常", ex);
                return -1;
            }
            return rn;
        }

        private void CreateChartSpectrum(bool reset)
        {
            int width = (int)spectrumCanvas.ActualWidth;
            int height = (int)spectrumCanvas.ActualHeight;

            if(width > 0 && height > 0)
            {
                // 设置image的size
                spectrumImage.Width = width;
                spectrumImage.Height = height;
            }

            SpectrumDisplayViewModel displayViewModel = windowViewModel.spectrumDisplayViewModel;

            if(lineChartSpectrum == null || reset)
            {
                Title chartTitle = new Title(new Padding(10, 10, 10, 5), "光谱图", new Font("Arial", 12, System.Drawing.FontStyle.Bold), new SolidBrush(System.Drawing.Color.Black));

                TitleProperty titlePropertyY = new TitleProperty();
                titlePropertyY.title = "强度(dBm)";
                titlePropertyY.titleTextFont = new Font("Arial", 10, System.Drawing.FontStyle.Bold);
                AxisTitle axisTitle = new AxisTitle(null, titlePropertyY, (int)Position.Left);

                AxisScaleWindow axisScaleWindow = new AxisScaleWindow();
                axisScaleWindow.scaleX.mode = SCALE_SHOW_MODE.Normal;

                axisScaleWindow.scaleX.valueRange.minValue = displayViewModel.waveLenRange.minValue;
                axisScaleWindow.scaleX.valueRange.maxValue = displayViewModel.waveLenRange.maxValue;


                ScaleLineProperty linePropertyX = new ScaleLineProperty();
                linePropertyX.color = System.Drawing.Color.LightGray;
                linePropertyX.width = 1;
                linePropertyX.type = LineType.LongDashed;
                axisScaleWindow.scaleX.lineProperty = linePropertyX;
                axisScaleWindow.scaleX.scaleTextFormat = "0:F3";

                axisScaleWindow.scaleY.mode = SCALE_SHOW_MODE.Normal;
                axisScaleWindow.scaleY.valueRange.minValue = displayViewModel.dBmRange.minValue;
                axisScaleWindow.scaleY.valueRange.maxValue = displayViewModel.dBmRange.maxValue;
                ScaleLineProperty linePropertyY = new ScaleLineProperty();
                linePropertyY.color = System.Drawing.Color.LightGray;
                linePropertyY.width = 1;
                linePropertyY.type = LineType.LongDashed;
                axisScaleWindow.scaleY.lineProperty = linePropertyY;

                axisScaleWindow.UpdateScaleValue();

                //参考线
                List<ReferenceLine> referenceLines = new List<ReferenceLine>();
                ObservableCollection<double> lineDataList = displayViewModel.referenceLines;
                foreach (var data in lineDataList)
                {
                    ReferenceLine line = new ReferenceLine(data);
                    referenceLines.Add(line);
                }
                axisScaleWindow.referenceLines = referenceLines;

                List<int> channelNoList = new List<int>();
                channelNoList.Add(1);

                Pen borderPen = new Pen(Color.Black, 1);
                ColorLegend colorLegend = MakeLegend(channelNoList, new Font("Arial", 8), borderPen);

                lineChartSpectrum = new LineChart(width, height, System.Drawing.Color.AliceBlue, chartTitle, axisTitle, axisScaleWindow, colorLegend);
                lineChartSpectrum.isColorLengendShow = false;
            }
            else
            {
                lineChartSpectrum.ReSize(width, height);
            }

            spectrumImage.Source = lineChartSpectrum.GetSource();

            lineChartSpectrum.Clear();
            lineChartSpectrum.Show(true);
        }

        private void ShowDataSpectrum(List<SpectrumPkgBuffer> spDataList)
        {
            if(lineChartSpectrum.elemList == null)
            {
                lineChartSpectrum.elemList = new List<List<ValuePoint>>();
            }

            lineChartSpectrum.elemList.Clear();

            ValueRange valueRangeX = new ValueRange();

            // 设置数据
            foreach(var data in spDataList)
            {
                List<ValuePoint> valuePoints = new List<ValuePoint>();

                //有可能接收的数据是不按照顺序的，需要排序后保证波长从小到大的顺序
                List<SpectrumAcqData> sortSubData = data.GetData().OrderBy(x => x.subPkgNo).ToList();
                foreach (var subData in sortSubData) 
                {  
                    for (int i = 0; i < subData.counts; i++) 
                    {
                        double valX = subData.startWaveLen + i * (subData.interval / 1000.0); 
                        double valY = subData.data[i];

                        valuePoints.Add(new ValuePoint(valX, valY));

                        if (double.IsNaN(valueRangeX.minValue))
                        {
                            valueRangeX.minValue = valX;
                        }
                        else if (valX < valueRangeX.minValue)
                        {
                            valueRangeX.minValue = valX;
                        }

                        if (double.IsNaN(valueRangeX.maxValue))
                        {
                            valueRangeX.maxValue = valX;
                        }
                        else if (valX > valueRangeX.maxValue)
                        {
                            valueRangeX.maxValue = valX;
                        }
                    }
                } 

                lineChartSpectrum.elemList.Add(valuePoints);
            }


            lineChartSpectrum.axisScaleWindow.scaleX.valueRange.minValue = valueRangeX.minValue;
            lineChartSpectrum.axisScaleWindow.scaleX.valueRange.maxValue = valueRangeX.maxValue;
            windowViewModel.spectrumDisplayViewModel.waveLenRange.minValue = valueRangeX.minValue;
            windowViewModel.spectrumDisplayViewModel.waveLenRange.maxValue = valueRangeX.maxValue;
            

            //设置图例
            List<ColorLegendData> colorLegendDataList = new List<ColorLegendData>();

            for (int i = 0; i < spDataList.Count; i++)
            {
                ColorLegendData newData = new ColorLegendData();
                newData.color = chSeriesColor[i];
                newData.text = "通道" + spDataList[i].channelNo;
                
                colorLegendDataList.Add(newData);
            }

            System.Drawing.Pen borderPen = new System.Drawing.Pen(System.Drawing.Color.Black, 1);
            ColorLegend colorLegend = new ColorLegend(colorLegendDataList, new Font("Arial", 8), borderPen, Position.TopRight);

            lineChartSpectrum.colorLegend = colorLegend;

            lineChartSpectrum.Show(true);
        }

        private ColorLegend MakeLegend(List<int> channelNoList, Font font, System.Drawing.Pen borderPen)
        {
            List<ColorLegendData> colorLegendDataList = new List<ColorLegendData>();

            foreach (var v in channelNoList)
            {
                ColorLegendData newData = new ColorLegendData();
                newData.color = chSeriesColor[v - 1];
                newData.text = "通道" + v.ToString();

                colorLegendDataList.Add(newData);
            }

            ColorLegend colorLegend = new ColorLegend(colorLegendDataList, font, borderPen, Position.TopRight);
            return colorLegend;

        }

        //private void ReadChannelSetting()
        //{
        //    ChannelItemViewModel selectedChannel = windowViewModel.spectrumDisplayViewModel.selectedChannelItem;
        //    if (selectedChannel == null) return;

        //    //os_ch_getting_item item = ReadChannelSettingItem(selectedChannel.no);
        //    ChannelParameter item = ReadChannelSettingItem(selectedChannel.no);
        //    if (item != null)
        //    {
        //        windowViewModel.chParamViewModel.threshold = item.threshold / 100.0;
        //        windowViewModel.chParamViewModel.refThreshold = item.refThreshold / 100.0;
        //        windowViewModel.chParamViewModel.width = item.width / 100.0;
        //        windowViewModel.chParamViewModel.widthLevel = item.widthLevel / 100.0;
                
        //    }
        //}

        private void ReadChannelSetting()
        {
            try
            {
                if(selectDeviceInfo == null)
                {
                    return;
                }
                DeviceClient client = TW_App.deviceClientManager.Find(selectDeviceInfo?.serialNo);
                client.dataWorker.ReadChParamter();
            }
            catch (Exception e)
            {
            }
        }

        private List<System.Drawing.Color> MakeLegendColorTable()
        {
            List<System.Drawing.Color> colorList = new List<System.Drawing.Color>();
            int r = 0, g = 0, b = 0;
            colorList.Add(System.Drawing.Color.FromArgb(0x00, 0xFF, 0x00));

            colorList.Add(System.Drawing.Color.FromArgb(0x00, 0x00, 0x00));

            colorList.Add(System.Drawing.Color.FromArgb(0xFF, 0x00, 0x00));
            
            colorList.Add(System.Drawing.Color.FromArgb(0x00, 0x00, 0xFF));

            colorList.Add(System.Drawing.Color.FromArgb(0xFF, 0xFF, 0x00));
            colorList.Add(System.Drawing.Color.FromArgb(0xFF, 0x00, 0xFF));
            colorList.Add(System.Drawing.Color.FromArgb(0x00, 0xFF, 0xFF));

            colorList.Add(System.Drawing.Color.FromArgb(0x80, 0x00, 0x00));
            colorList.Add(System.Drawing.Color.FromArgb(0x00, 0x80, 0x00));
            colorList.Add(System.Drawing.Color.FromArgb(0x00, 0x00, 0x80));

            colorList.Add(System.Drawing.Color.FromArgb(0x80, 0x80, 0x00));
            colorList.Add(System.Drawing.Color.FromArgb(0x80, 0x00, 0x80));
            colorList.Add(System.Drawing.Color.FromArgb(0x00, 0x80, 0x80));

            colorList.Add(System.Drawing.Color.FromArgb(0xFF, 0xB0, 0xB0));
            colorList.Add(System.Drawing.Color.FromArgb(0x80, 0x80, 0x80));
            colorList.Add(System.Drawing.Color.FromArgb(0xFF, 0x40, 0x40));

            colorList.Add(System.Drawing.Color.FromArgb(0xA0, 0x80, 0x20));
            colorList.Add(System.Drawing.Color.FromArgb(0x20, 0x80, 0x20));


            colorList.Add(System.Drawing.Color.FromArgb(0x32, 0xCD, 0x32));
            colorList.Add(System.Drawing.Color.FromArgb(0x48, 0xD1, 0xCC));
            colorList.Add(System.Drawing.Color.FromArgb(0x64, 0x95, 0xED));
            colorList.Add(System.Drawing.Color.FromArgb(0x41, 0x69, 0xE1));
            colorList.Add(System.Drawing.Color.FromArgb(0xEE, 0x82, 0xEE));
            colorList.Add(System.Drawing.Color.FromArgb(0x8A, 0x2B, 0xE2));
            colorList.Add(System.Drawing.Color.FromArgb(0xDB, 0x70, 0x93));
            colorList.Add(System.Drawing.Color.FromArgb(0xFF, 0xE4, 0xE1));
            colorList.Add(System.Drawing.Color.FromArgb(0x70, 0x80, 0x90));
            colorList.Add(System.Drawing.Color.FromArgb(0xD2, 0x69, 0x1E));
            colorList.Add(System.Drawing.Color.FromArgb(0xF0, 0x80, 0x80));
            colorList.Add(System.Drawing.Color.FromArgb(0xDC, 0x14, 0x3C));
            colorList.Add(System.Drawing.Color.FromArgb(0xFF, 0xD7, 0x00));
            colorList.Add(System.Drawing.Color.FromArgb(0xFF, 0xFA, 0xCD));

            return colorList;
        }
        #endregion

        #region 波形相关
        private LineChart lineChartWaveLen;

        private void CreateChartWaveLen(bool reset)
        {
            WaveLenDisplaySettingViewModel settingViewModel = windowViewModel.waveLenDisplaySetting;

            int width = (int)waveLenCanvas.ActualWidth;
            int height = (int)waveLenCanvas.ActualHeight;

            if(width > 0 && height > 0)
            {
                waveLenImage.Width = width;
                waveLenImage.Height = height;
            }

            if(lineChartWaveLen == null || reset)
            {
                System.Drawing.Pen borderPen = new System.Drawing.Pen(System.Drawing.Color.Black, 1);

                Title chartTitle = new Title(new Padding(10, 10, 10, 5), "实时波形", new Font("Arial", 12, System.Drawing.FontStyle.Bold), new SolidBrush(System.Drawing.Color.Black));

                TitleProperty titlePropertyY = new TitleProperty();
                titlePropertyY.title = "波长(nm)";
                titlePropertyY.titleTextFont = new Font("Arial", 10, System.Drawing.FontStyle.Bold);
                AxisTitle axisTitle = new AxisTitle(null, titlePropertyY, (int)Position.Left);

                AxisScaleWindow axisScaleWindow = new AxisScaleWindow();
                axisScaleWindow.scaleX.mode = SCALE_SHOW_MODE.Normal;
                axisScaleWindow.scaleX.valueRange.minValue = settingViewModel.valueRangeX.minValue;
                axisScaleWindow.scaleX.valueRange.maxValue = settingViewModel.valueRangeX.maxValue;
                axisScaleWindow.scaleX.scaleTextFormat = "0:F0";
                ScaleLineProperty linePropertyX = new ScaleLineProperty();
                linePropertyX.color = Color.LightGray;
                linePropertyX.width = 1;
                linePropertyX.type = LineType.Solid;
                axisScaleWindow.scaleX.lineProperty = linePropertyX;

                axisScaleWindow.scaleY.mode = SCALE_SHOW_MODE.Readable;
                axisScaleWindow.scaleY.valueRange.minValue = settingViewModel.valueRangeY.minValue;
                axisScaleWindow.scaleY.valueRange.maxValue = settingViewModel.valueRangeY.maxValue;
                axisScaleWindow.scaleY.scaleTextFormat = "0:F3";
                ScaleLineProperty linePropertyY = new ScaleLineProperty();
                linePropertyY.color = Color.LightGray;
                linePropertyY.width = 1;
                linePropertyY.type = LineType.Solid;
                axisScaleWindow.scaleY.lineProperty = linePropertyY;
                axisScaleWindow.UpdateScaleValue();

                List<ColorLegendData> colorLegendDataList = new List<ColorLegendData>();


                ColorLegend colorLegend = new ColorLegend(colorLegendDataList, new Font("Arial", 8), borderPen, Position.TopRight);

                lineChartWaveLen = new LineChart(width, height, System.Drawing.Color.AliceBlue, chartTitle, axisTitle, axisScaleWindow, null);
                lineChartWaveLen.isColorLengendShow = false;

                lineChartWaveLen.elemList = new List<List<ValuePoint>>();

            }
            else
            {
                lineChartWaveLen.ReSize(width, height);
            }

            waveLenImage.Source = lineChartWaveLen.GetSource();

            lineChartWaveLen.Clear();
            lineChartWaveLen.Show(true);
        }
        #endregion
    }

    #region ViewModel
    public class MainWindowViewModel : ViewModelBase
    {
        private DeviceInfoCollection deviceInfoCollection;
        

        public MainWindowViewModel()
        {
            title = TW_App.TITLE + " v" + TW_App.VERSION;

            deviceInfoCollection = TW_App.deviceInfoCollection.Clone();
           

            deviceInfos = new ObservableCollection<DeviceInfoViewModel>();
            deviceInfoCollection.ForEach(x =>
            {
                DeviceInfoViewModel deviceInfo = new DeviceInfoViewModel(x);
                deviceInfo.continuousRunTime = 0;
                deviceInfo.status = model.DeviceStatus.NORMALI;
                deviceInfos.Add(deviceInfo);
                return false;
            });

            spectrumDisplayViewModel = new SpectrumDisplayViewModel();
            channelItems = new ObservableCollection<ChannelItemViewModel>();
            for(int i = 1; i <= 32; i++)
            {
                ChannelItemViewModel ci = new ChannelItemViewModel();
                ci.no = i;
                ci.name = "通道" + i;
                channelItems.Add(ci);
            }

            spectrumDisplayViewModel.selectedChannelItem = channelItems[0];

            chParamViewModel = new ChParamViewModel();

            waveLenDisplaySetting = new WaveLenDisplaySettingViewModel();
            waveLenDisplaySetting.valueRangeX.minValue = 0;
            waveLenDisplaySetting.valueRangeX.maxValue = 1000;
            waveLenDisplaySetting.valueRangeY.minValue = 1510;
            waveLenDisplaySetting.valueRangeY.maxValue = 1590;

            grattingItems = new ObservableCollection<ChannelItemViewModel>();
            for (int i = 1; i <= 32; i++)
            {
                ChannelItemViewModel ci = new ChannelItemViewModel();
                ci.no = i;
                ci.name = "光栅" + i;
                grattingItems.Add(ci);
            }
            waveLenDisplaySetting.selectedGrattingNo = grattingItems[0];
        }

        //public void Reload()
        //{
        //    deviceInfoCollection = TW_App.deviceInfoCollection.Clone();
        //    deviceInfos.Clear();
        //    deviceInfoCollection.ForEach(x =>
        //    {
        //        DeviceInfoViewModel deviceInfo = new DeviceInfoViewModel(x);
        //        deviceInfos.Add(deviceInfo);
        //        return false;
        //    });
        //}

        private ObservableCollection<DeviceInfoViewModel> m_deviceInfos;
        public ObservableCollection<DeviceInfoViewModel> deviceInfos
        {
            get { return m_deviceInfos; }
            set
            {
                m_deviceInfos = value;
                NotifyPropertyChanged();
            }
        }

        private SpectrumDisplayViewModel m_spectrumDisplayViewModel;
        public SpectrumDisplayViewModel spectrumDisplayViewModel
        {
            get { return m_spectrumDisplayViewModel; }
            set
            {
                m_spectrumDisplayViewModel = value;
                NotifyPropertyChanged();
            }
        }

        private ObservableCollection<ChannelItemViewModel> m_channelItems;
        public ObservableCollection<ChannelItemViewModel> channelItems
        {
            get { return m_channelItems; }
            set
            {
                m_channelItems = value;
                NotifyPropertyChanged();
            }
        }

        private ChParamViewModel m_chParamViewModel;
        public ChParamViewModel chParamViewModel
        {
            get { return m_chParamViewModel; }
            set
            {
                m_chParamViewModel = value;
                NotifyPropertyChanged();
            }
        }

        private ObservableCollection<ChannelItemViewModel> m_grattingItems;
        public ObservableCollection<ChannelItemViewModel> grattingItems
        {
            get { return m_grattingItems; }
            set
            {
                m_grattingItems = value;
                NotifyPropertyChanged();
            }
        }

        private WaveLenDisplaySettingViewModel m_waveLenDisplaySetting;
        public WaveLenDisplaySettingViewModel waveLenDisplaySetting
        {
            get { return m_waveLenDisplaySetting; }
            set
            {
                m_waveLenDisplaySetting = value;
                NotifyPropertyChanged();
            }
        }

        private double m_waveLenCurrentValue;
        public double waveLenCurrentValue
        {
            get { return m_waveLenCurrentValue; }
            set
            {
                m_waveLenCurrentValue = value;
                NotifyPropertyChanged();
            }
        }

        private string m_title;
        public string title
        {
            get { return m_title; }
            set
            {
                m_title = value;
                NotifyPropertyChanged();
            }
        }
    }

    #endregion
}
